diff --git a/.gitignore b/.gitignore index 5ff56e58..b4a52775 100644 --- a/.gitignore +++ b/.gitignore @@ -1,30 +1,3 @@ -/target/ -!.mvn/wrapper/maven-wrapper.jar -/logs -.svn - -### STS or Eclipse ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws +.idea/ +target/ *.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -/build/ - -### VS Code ### -.vscode/ \ No newline at end of file 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 d1142214..e9df21cd 100644 --- a/README.md +++ b/README.md @@ -1,102 +1,18 @@ -# 1. Java基础 - - - -# 2. 设计模式 - -[设计模式](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern) - -## 2.1 前导 - -学设计模式最好有以下两点知识基础。 - -[软件设计七大原则](https://www.cnblogs.com/gj-blog/p/10929440.html) - -[UML类图以及类与类之间的关系](https://www.cnblogs.com/gj-blog/p/10929447.html) - -原因: -- 设计模式是围绕着软件设计七大原则来说的,每一种设计模式通常会满足一到两三种软件设计原则,同时又可能违反某一种原则。学习这些原则可以理解该设计模式适用什么业务场景以及为什么要这样做。 -- 设计模式通常都伴随着面向对象的特性(封装、继承、多态),所以会涉及到大量的类与类之间的关系。通过画类图可以更好的理解设计模式。 - -## 2.2 设计模式分类 - -### 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.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.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. 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/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 new file mode 100644 index 00000000..88f18783 --- /dev/null +++ b/algorithms/algorithm/pom.xml @@ -0,0 +1,15 @@ + + + + algorithms + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + algorithm + + + \ No newline at end of file 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/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/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/pom.xml b/algorithms/datastructure/pom.xml new file mode 100644 index 00000000..20c2b585 --- /dev/null +++ b/algorithms/datastructure/pom.xml @@ -0,0 +1,16 @@ + + + + algorithms + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + cn.lastwhisper + datastructure + + + \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/graph/Graph.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/graph/Graph.java new file mode 100644 index 00000000..4f69cc9f --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/graph/Graph.java @@ -0,0 +1,218 @@ +package cn.lastwhisper.atguigu.graph; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 图 + * @author cn.lastwhisper + */ +public class Graph { + private List vertexList; // 存储顶点集合 + private int[][] matrix; // 存储图对应的邻接矩阵 + private int numOfEdges; // 记录边的数量 + private boolean[] isVisited; // 记录某节点是否被访问 + + // 初始化图的参数 + public Graph(int n) { + vertexList = new ArrayList<>(n); + matrix = new int[n][n]; + //isVisited = new boolean[n]; + numOfEdges = 0; + } + + public static void main(String[] args) { + // 顶点 + //String[] vertexs = {"A", "B", "C", "D", "E"}; + String[] vertexs = {"1", "2", "3", "4", "5", "6", "7", "8"}; + //创建图对象 + Graph graph = new Graph(vertexs.length); + //循环的添加顶点 + for (String vertex : vertexs) { + graph.addVertex(vertex); + } + //添加边 + //A-B A-C B-C B-D B-E + //graph.addEdge(0, 1, 1); // A-B + //graph.addEdge(0, 2, 1); // + //graph.addEdge(1, 2, 1); // + //graph.addEdge(1, 3, 1); // + //graph.addEdge(1, 4, 1); // + graph.addEdge(0, 1, 1); + graph.addEdge(0, 2, 1); + graph.addEdge(1, 3, 1); + graph.addEdge(1, 4, 1); + graph.addEdge(3, 7, 1); + graph.addEdge(4, 7, 1); + graph.addEdge(2, 5, 1); + graph.addEdge(2, 6, 1); + graph.addEdge(5, 6, 1); + //graph.show(); + System.out.println("深度优先:"); + graph.dfs(); + System.out.println("广度优先:"); + graph.bfs(); + } + + //遍历所有的节点,都进行广度优先搜索 + public void bfs() { + isVisited = new boolean[vertexList.size()]; + for (int i = 0; i < getNumOfVertex(); i++) { + if (!isVisited[i]) { + bfs(isVisited, i); + } + } + System.out.println(); + } + + // 广度优先 + public void bfs(boolean[] isVisited, int i) { + 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的第一个邻接节点下标 + w = getFristNeighbor(u); + while (w != -1) { + if (!isVisited[w]) { + System.out.print(getValueByIndex(w) + "=>"); + // 标记节点已经访问 + isVisited[w] = true; + //入队,用于下一次出队 + queue.addLast(w); + } + // 从队列头节点,找到邻接节点w之后的邻接节点 + w = getNextNeighbor(u, w); + } + } + } + + public void dfs() { + isVisited = new boolean[vertexList.size()]; + for (int i = 0; i < getNumOfVertex(); i++) { + if (!isVisited[i]) { + // 0,1,2,3,4,5 + dfs(isVisited, 0); + } + } + System.out.println(); + } + + // 深度优先遍历算法 + public void dfs(boolean[] isVisited, int i) { + // 首先我们访问该节点,输出 + System.out.print(getValueByIndex(i) + "->"); + // 将节点设置为已经访问 + isVisited[i] = true; + // 查找节点i的第一个邻接节点j + int w = getFristNeighbor(i); + while (w != -1) { + if (!isVisited[w]) { + dfs(isVisited, w); + } + // 第i个节点下标i,matrix的row;w是邻接节点下标,matrix的column + w = getNextNeighbor(i, w); + } + } + + /** + * 根据前一个邻接节点的下标来获取下一个邻接节点 + * + * 0 1 2 3 4 + * A B C D E + * 0 A[0, 1, 1, 0, 0] + * 1 B[1, 0, 1, 1, 1] + * 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 + * @param v1 当前weight横下标 + * @param v2 当前weight纵下标 + * @return int + */ + public int getNextNeighbor(int v1, int v2) { + for (int i = v2 + 1; i < getNumOfVertex(); i++) { + if (matrix[v1][i] > 0) { + return i; + } + } + return -1; + } + + /** + * 得到某一个节点的第一个邻接节点的下标 + * 例如: + * 0 1 2 3 4 + * A B C D E + * 0 A[0, 1, 1, 0, 0] + * 1 B[1, 0, 1, 1, 1] + * 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 某一个节点 + * @return int + */ + public int getFristNeighbor(int index) { + for (int i = 0; i < getNumOfVertex(); i++) { + if (matrix[index][i] > 0) { + return i; + } + } + return -1; + } + + // 返回节点下标对应的数据 + public String getValueByIndex(int i) { + return vertexList.get(i); + } + + // 添加节点 + public void addVertex(String vertex) { + vertexList.add(vertex); + } + + /** + * 添加边 + * + * @param v1 节点1的下标 + * @param v2 节点2的下标 + * @param weight 1表示有通路,0表示无通路 + */ + public void addEdge(int v1, int v2, int weight) { + matrix[v1][v2] = weight; + matrix[v2][v1] = weight; + numOfEdges++; + } + + // 显示图对应矩阵 + public void show() { + for (int i = 0; i < matrix.length; i++) { + System.out.println(Arrays.toString(matrix[i])); + } + } + + //返回节点的个数 + public int getNumOfVertex() { + return vertexList.size(); + } + + //得到边的数目 + public int getNumOfEdges() { + return numOfEdges; + } + + //返回v1和v2的权值 + public int getWeight(int v1, int v2) { + return matrix[v1][v2]; + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/hashtab/HashTabDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/hashtab/HashTabDemo.java new file mode 100644 index 00000000..8eb6eee7 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/hashtab/HashTabDemo.java @@ -0,0 +1,193 @@ +package cn.lastwhisper.atguigu.hashtab; + +/** + * + * @author cn.lastwhisper + */ +public class HashTabDemo { + public static void main(String[] args) { + // EmpLinkedList测试 + //Emp emp1 = new Emp(1, "tom"); + //Emp emp2 = new Emp(2, "condy"); + //EmpLinkedList empLinkedList = new EmpLinkedList(); + //empLinkedList.add(emp1); + //empLinkedList.add(emp2); + //empLinkedList.list(); + //Emp empById = empLinkedList.findEmpById(2); + //System.out.printf("id:%d-->name:%s\t", empById.id, empById.name); + + Emp emp1 = new Emp(1, "tom"); + Emp emp2 = new Emp(2, "condy"); + HashTable hashTable = new HashTable(7); + hashTable.add(emp1); + hashTable.add(emp2); + Emp emp9 = new Emp(9, "kangkang"); + hashTable.add(emp9); + hashTable.list(); + + System.out.println("===============根据id查找=============="); + System.out.println(hashTable.findEmpById(9)); + System.out.println("===============根据id更新=============="); + hashTable.update(new Emp(9, "jackma")); + System.out.println(hashTable.findEmpById(9)); + System.out.println("===============根据id删除=============="); + hashTable.delete(9); + hashTable.list(); + } +} + +// 哈希表 +class HashTable { + private EmpLinkedList[] empLinkedLists; + private int size; + + public HashTable(int size) { + this.size = size; + empLinkedLists = new EmpLinkedList[size]; + for (int i = 0; i < empLinkedLists.length; i++) { + empLinkedLists[i] = new EmpLinkedList(); + } + } + + // 添加 + public void add(Emp emp) { + EmpLinkedList empLinkedList = empLinkedLists[hashFun(emp.id)]; + empLinkedList.add(emp); + } + + // 根据id查找 + public Emp findEmpById(int id) { + EmpLinkedList empLinkedList = empLinkedLists[hashFun(id)]; + Emp emp = empLinkedList.findEmpById(id); + return emp; + } + + // 修改 + public void update(Emp emp) { + EmpLinkedList empLinkedList = empLinkedLists[hashFun(emp.id)]; + empLinkedList.update(emp); + } + + // 删除 + public void delete(int id) { + EmpLinkedList empLinkedList = empLinkedLists[hashFun(id)]; + empLinkedList.delete(id); + } + + // 展示节点 + public void list() { + for (int i = 0; i < empLinkedLists.length; i++) { + System.out.printf("第%d个链表:", i + 1); + empLinkedLists[i].list(); + } + } + + // hash函数 + public int hashFun(int id) { + return id % size; + } + +} + +// 链表 +class EmpLinkedList { + private Emp head; + + // 添加 + public void add(Emp emp) { + // 第一个元素 + if (head == null) { + head = emp; + return; + } + // 将链表最后一个节点.next=待添加节点添加 + Emp currEmp = head; + while (currEmp.next != null) { + currEmp = currEmp.next; + } + currEmp.next = emp; + } + + // 根据id查找 + public Emp findEmpById(int empId) { + Emp currEmp = head; + if (currEmp == null) { + System.out.println("链表元素为空"); + return null; + } + while (currEmp != null) { + if (currEmp.id == empId) { + return currEmp; + } + currEmp = currEmp.next; + } + return null; + } + + // 修改 + public void update(Emp emp) { + Emp currEmp = head; + if (currEmp == null) { + System.out.println("链表元素为空"); + return; + } + while (currEmp != null) { + if (currEmp.id == emp.id) { + currEmp.name = emp.name; + break; + } + currEmp = currEmp.next; + } + } + + // 删除 + public void delete(int id) { + Emp currEmp = head; + if (currEmp == null) { + System.out.println("链表元素为空"); + return; + } + + while (currEmp != null) { + if (currEmp.next.id == id) { + currEmp.next = currEmp.next.next; + break; + } + currEmp = currEmp.next; + } + } + + // 展示节点 + public void list() { + Emp currEmp = head; + if (currEmp == null) { + System.out.println("链表元素为空"); + return; + } + while (currEmp != null) { + System.out.printf("id:%d-->name:%s\t", currEmp.id, currEmp.name); + currEmp = currEmp.next; + } + System.out.println(); + } +} + +// 员工节点 +class Emp { + public int id; + public String name; + public Emp next; + + public Emp(int id, String name) { + this.id = id; + this.name = name; + } + + @Override + public String toString() { + return "Emp{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/DoubleLinkedListDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/DoubleLinkedListDemo.java new file mode 100644 index 00000000..8d725b43 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/DoubleLinkedListDemo.java @@ -0,0 +1,179 @@ +package cn.lastwhisper.atguigu.linkedlist; + +/** + * 双向链表 + * @author cn.lastwhisper + */ +public class DoubleLinkedListDemo { + public static void main(String[] args) { + DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); + HeroNode2 hero1 = new HeroNode2(1, "宋江", "及时雨"); + HeroNode2 hero2 = new HeroNode2(2, "卢俊义", "玉麒麟"); + HeroNode2 hero3 = new HeroNode2(3, "吴用", "智多星"); + HeroNode2 hero4 = new HeroNode2(4, "林冲", "豹子头"); + doubleLinkedList.add(hero1); + doubleLinkedList.add(hero2); + doubleLinkedList.add(hero3); + doubleLinkedList.add(hero4); + System.out.println("===============查看链表所有节点================"); + doubleLinkedList.list(); + System.out.println("===============删除链表某节点=================="); + doubleLinkedList.delete(2); + System.out.println("===============查看链表所有节点================"); + doubleLinkedList.list(); + System.out.println("================更新链表节点,4================="); + doubleLinkedList.update(new HeroNode2(4, "林冲", "豹子头~~~")); + System.out.println("===============查看链表所有节点================"); + doubleLinkedList.list(); + System.out.println("===============按序插入节点,8================"); + doubleLinkedList.addByNoOrder(new HeroNode2(8, "武松", "行者")); + System.out.println("===============查看链表所有节点================"); + doubleLinkedList.list(); + System.out.println("===============按序插入节点,6================"); + doubleLinkedList.addByNoOrder(new HeroNode2(6, "入云龙", "公孙胜")); + System.out.println("===============查看链表所有节点================"); + doubleLinkedList.list(); + } +} + +class DoubleLinkedList { + HeroNode2 head = new HeroNode2(0, "", ""); + + /** + * 添加 + */ + public void add(HeroNode2 newNode) { + HeroNode2 tempNode = head; + while (true) { + if (tempNode.next == null) { + break; + } + tempNode = tempNode.next; + } + // lastNode.next指向newNode + tempNode.next = newNode; + // newNode.pre指向lastNode + newNode.pre = tempNode; + } + + /** + * 删除 + */ + public void delete(int no) { + HeroNode2 tempNode = head; + while (true) { + if (tempNode.next == null) { + 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); + break; + } + } + } + + // 修改 + public void update(HeroNode2 updateNode) { + HeroNode2 tempNode = head; + while (true) { + if (tempNode.next == null) { + 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); + break; + } + } + } + + /** + * 展示所有节点,沿着头节点遍历 + * + * @param + * @return void + */ + public void list() { + HeroNode2 currNode = head.next; + while (currNode != null) { + System.out.printf("%d\t%s\t%s\t\n", currNode.no, currNode.name, currNode.nickName); + currNode = currNode.next; + } + } + + /** + * 根据排名插入到指定位置 + * 如果已存在该排名添加失败 + * + * @param heroNode + * @return void + */ + public void addByNoOrder(HeroNode2 heroNode) { + HeroNode2 tempNode = head; + //HeroNode2 preNode; + boolean flag = true; + while (true) { + if (tempNode.next == null) { + break; + } + //preNode = tempNode; + tempNode = tempNode.next; + // tempNode是待插入节点的前一个节点 + if (heroNode.no == tempNode.no) { + flag = false; + System.out.println("已存在排名,添加失败" + heroNode); + break; + } + + if (heroNode.no < tempNode.no) { + // 1,3,4 heroNode.no=2 tempNode.next.no=3 2<3 可以添加 + // heroNode指向no=3节点,即2,3 + heroNode.next = tempNode; + // tempNode.pre为no=1的节点 即1,2 + // preNode.next = heroNode; + tempNode.pre.next = heroNode; + flag = false; + break; + } + } + if (flag) { + // 待插入节点no最大 + tempNode.next = heroNode; + heroNode.pre = tempNode; + } + } +} + +/** + * 双向链表节点 + * + */ +class HeroNode2 { + public int no; + public String name; + public String nickName; + public HeroNode2 next; // 当前节点的后一个节点 + public HeroNode2 pre; //当前节点的前一个节点 + + public HeroNode2(int no, String name, String nickName) { + this.no = no; + this.name = name; + this.nickName = nickName; + } + + @Override + public String toString() { + return "HeroNode2{" + + "no=" + no + + ", name='" + name + '\'' + + ", nickName='" + nickName + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/Josepfu.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/Josepfu.java new file mode 100644 index 00000000..05df13fc --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/Josepfu.java @@ -0,0 +1,135 @@ +package cn.lastwhisper.atguigu.linkedlist; + +/** + * 约瑟夫环 + * @author cn.lastwhisper + */ +public class Josepfu { + public static void main(String[] args) { + CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(); + circleSingleLinkedList.createCircle(5); + circleSingleLinkedList.showBoy(); + System.out.println(); + circleSingleLinkedList.calc(1, 2, 5); + + } +} + +/** + * 单向环形链表 + */ +class CircleSingleLinkedList { + private Boy frist; + + /** + * 创建单向环形链表 + * + * @param num + * @return void + */ + public void createCircle(int num) { + if (num < 1) { + System.out.println("错误的num"); + return; + } + // 定位最后一个boy的位置,方便添加节点 + Boy currBoy = null; + for (int i = 1; i <= num; i++) { + Boy boy = new Boy(i); + if (i == 1) { + // 只有一个boy + frist = boy; + frist.setNext(frist); + currBoy = boy; + } else { + // 在已有环链的基础上添加 + currBoy.setNext(boy); + boy.setNext(frist); + currBoy = boy; + } + } + } + + /** + * 打印当前环链的节点信息 + */ + public void showBoy() { + if (frist == null) { + System.out.println("没有小孩"); + return; + } + Boy currBoy = frist; + while (true) { + System.out.printf("%d ", currBoy.getNo()); + currBoy = currBoy.getNext(); + if (currBoy == frist) { + break; + } + } + + } + + /** + * 有n个人的环,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,写出出队序列. + * + * @param k 从第几个小孩开始 + * @param m 数几次 + * @param n 总人数 + * @return void + */ + public void calc(int k, int m, int n) { + // 1、数据校验 + // 2、pre指针,让pre指针移动到frist指针前一个位置 + Boy preNode = frist; + while (preNode.getNext() != frist) { + preNode = preNode.getNext(); + } + // 3、报数前,让frist、pre指针同时移动k-1次,进入起始位置 + for (int i = 0; i < k - 1; i++) { + frist = frist.getNext(); + preNode = preNode.getNext(); + } + // 4、报数时,让frist、pre指针同时移动m-1次,frist指针进入待移除位置,输出待移除位置的编号 + // frist再向前移一位,pre.next=frist,完成小孩出队。 + // 5、重复第四步,直至还剩一个小孩 + while (true) { + if (frist.getNo() == preNode.getNo()) { + System.out.printf("最后留在圈中小孩编号:%d\n", frist.getNo()); + break; + } + for (int i = 0; i < m - 1; i++) { + frist = frist.getNext(); + preNode = preNode.getNext(); + } + System.out.printf("小孩出圈编号为:%d\n", frist.getNo()); + frist = frist.getNext(); + preNode.setNext(frist); + } + } + +} + +class Boy { + private int no; //编号 + private Boy next; + + public Boy(int no) { + this.no = no; + } + + public int getNo() { + return no; + } + + public void setNo(int no) { + this.no = no; + } + + public Boy getNext() { + return next; + } + + public void setNext(Boy next) { + this.next = next; + } +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/SingleLinkedListDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/SingleLinkedListDemo.java new file mode 100644 index 00000000..6f915a4d --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/SingleLinkedListDemo.java @@ -0,0 +1,451 @@ +package cn.lastwhisper.atguigu.linkedlist; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; +import java.util.Stack; + +/** + * 单链表的功能实现:增删改查 + * 有序插入、有序合并、删除重复节点 + * @author cn.lastwhisper + */ +public class SingleLinkedListDemo { + static SingleLinkedList singleLinkedList = new SingleLinkedList(); + static HeroNode hero1 = new HeroNode(1, "宋江", "及时雨"); + static HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟"); + static HeroNode hero3 = new HeroNode(3, "吴用", "智多星"); + static HeroNode hero4 = new HeroNode(4, "林冲", "豹子头"); + + static { + singleLinkedList.add(hero1); + singleLinkedList.add(hero2); + singleLinkedList.add(hero3); + singleLinkedList.add(hero4); + } + + public static void main(String[] args) { + + System.out.println("===============查看链表所有节点================"); + singleLinkedList.list(); + System.out.println("===============删除链表某节点=================="); + singleLinkedList.delete(2); + System.out.println("===============查看链表所有节点================"); + singleLinkedList.list(); + System.out.println("================更新链表节点,4================="); + singleLinkedList.update(new HeroNode(4, "林冲", "豹子头~~~")); + System.out.println("===============查看链表所有节点================"); + singleLinkedList.list(); + 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("===============查看链表所有节点================"); + singleLinkedList.list(); + System.out.println("===============按序插入节点,8================"); + singleLinkedList.addByNoOrder(new HeroNode(8, "武松", "行者")); + System.out.println("===============查看链表所有节点================"); + singleLinkedList.list(); + System.out.println("===============按序插入节点,7================"); + singleLinkedList.addByNoOrder(new HeroNode(7, "入云龙", "公孙胜")); + System.out.println("===============查看链表所有节点================"); + singleLinkedList.list(); + System.out.println("---------------获取链表长度,不包括头节点-----------"); + System.out.println(singleLinkedList.size()); + System.out.println("---------------获取链表倒数第2个元素-----------"); + System.out.println(singleLinkedList.findLastIndexNode(2)); + System.out.println("---------------反转单链表--------------"); + singleLinkedList.reverse(); + singleLinkedList.list(); + System.out.println("---------------反转单链表--------------"); + singleLinkedList.reverse(); + System.out.println("---------------从尾到头打印单链表---------------"); + singleLinkedList.reverseList(); + + System.out.println("---------------合并有序单链表---------------"); + SingleLinkedList singleLinkedList2 = new SingleLinkedList(); + HeroNode hero21 = new HeroNode(1, "宋江", "及时雨"); + HeroNode hero23 = new HeroNode(3, "卢俊义", "玉麒麟"); + HeroNode hero25 = new HeroNode(6, "吴用", "智多星"); + HeroNode hero27 = new HeroNode(7, "林冲", "豹子头"); + singleLinkedList2.add(hero21); + singleLinkedList2.add(hero23); + singleLinkedList2.add(hero25); + singleLinkedList2.add(hero27); + System.out.println("---------------查看二号链表所有节点---------------"); + singleLinkedList2.list(); + SingleLinkedList singleLinkedList3 = new SingleLinkedList(); + HeroNode hero32 = new HeroNode(2, "柴进", "小旋风"); + HeroNode hero34 = new HeroNode(4, "鲁智深", "花和尚"); + HeroNode hero36 = new HeroNode(6, "石秀", "拼命三郎"); + HeroNode hero38 = new HeroNode(8, "秦明", "霹雳火"); + singleLinkedList3.add(hero32); + singleLinkedList3.add(hero34); + singleLinkedList3.add(hero36); + singleLinkedList3.add(hero38); + System.out.println("---------------查看三号链表所有节点---------------"); + singleLinkedList3.list(); + System.out.println("-----------------合并结束-------------------"); + singleLinkedList2.mergeOrderLinkedList(singleLinkedList3); + System.out.println("-----------------查看二号链表所有节点-----------------"); + singleLinkedList2.list(); + } + + // 测试删除重复节点 + @Test + public void testDeleteDuplicate() { + HeroNode hero5 = new HeroNode(5, "宋江", "豹子头"); + singleLinkedList.add(hero5); + singleLinkedList.deleteDuplicate(); + singleLinkedList.list(); + } + +} + +/** + * 单链表 + * + */ +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; + } + tempNode = tempNode.next; + } + tempNode.next = heroNode; + } + + /** + * 根据排名插入到指定位置 + * 如果已存在该排名添加失败 + * + * @param heroNode + * @return void + */ + public void addByNoOrder(HeroNode heroNode) { + HeroNode tempNode = head; + HeroNode preNode; + boolean flag = true; + while (true) { + if (tempNode.next == null) { + break; + } + preNode = tempNode; + tempNode = tempNode.next; + + if (heroNode.no == tempNode.no) { + flag = false; + System.out.println("已存在排名,添加失败" + heroNode); + break; + } + + if (heroNode.no < tempNode.no) { + // 1,3,4 heroNode.no=2 tempNode.next.no=3 2<3 可以添加 + // heroNode指向no=3节点 + heroNode.next = tempNode; + // tempNode指向heroNode节点 + preNode.next = heroNode; + flag = false; + break; + } + } + if (flag) { + // 待插入节点no最大 + tempNode.next = heroNode; + } + } + + /** + * 根据排名插入到指定位置 + * 可以存在相同编号的节点 + * @param heroNode + * @return void + */ + public void addByNoOrderIsEqual(HeroNode heroNode) { + HeroNode tempNode = head; + HeroNode preNode; + boolean flag = true; + while (true) { + if (tempNode.next == null) { + break; + } + preNode = tempNode; + tempNode = tempNode.next; + + if (heroNode.no <= tempNode.no) { + // 1,3,4 heroNode.no=2 tempNode.next.no=3 2<3 可以添加 + // heroNode指向no=3节点 + heroNode.next = tempNode; + // tempNode指向heroNode节点 + preNode.next = heroNode; + flag = false; + break; + } + } + if (flag) { + // 待插入节点no最大 + tempNode.next = heroNode; + } + } + + /** + * 展示所有节点,沿着头节点遍历 + * + * @param + * @return void + */ + public void list() { + HeroNode currNode = head.next; + while (currNode != null) { + System.out.printf("%d\t%s\t%s\t\n", currNode.no, currNode.name, currNode.nickName); + currNode = currNode.next; + } + } + + + /** + * 删除链表中重复的元素 + */ + public void deleteDuplicate() { + Set set = new HashSet<>(); + HeroNode currNode = head.next; + HeroNode preNode = null; + while (currNode != null) { + if (set.contains(currNode.name)) { + preNode.next = currNode.next; + } else { + set.add(currNode.name); + preNode = currNode; + } + currNode = currNode.next; + } + + } + + /** + * 根据no删除节点 + * + * @param no + * @return void + */ + public void delete(int no) { + // 1、沿着头节点tempNode遍历,找到node.no=no的前一个节点preNode + HeroNode preNode = head; + while (true) { + if (preNode.next == null) { + System.out.printf("未找到no==%d 节点\n", no); + break; + } + // tempNode是待删除节点的前一个节点 + preNode = preNode.next; + // 2. 找到待删除节点的前一个节点 + if (preNode.next.no == no) { + preNode.next = preNode.next.next; + System.out.printf("已删除no==%d 节点\n", no); + break; + } + } + } + + /** + * 根据no更新节点 + * + * @param updateNode + * @return void + */ + public void update(HeroNode updateNode) { + HeroNode tempNode = head; + while (true) { + if (tempNode.next == null) { + 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); + break; + } + } + } + + /** + * 获取单链表的节点个数(不统计头节点) + * + * @param + * @return int + */ + public int size() { + HeroNode currNode = head.next; + int counter = 0; + while (currNode != null) { + counter++; + currNode = currNode.next; + } + return counter; + } + + /** + * 获取单链表倒数第k个节点 + * 思路:倒数第k个等价于正数size-k+1个 + * 示例:7个元素,倒数第2个==正数第6个 + * @param k + * @return cn.cn.lastwhisper.linkedlist.HeroNode + */ + public HeroNode findLastIndexNode(int k) { + int end = size() - k; + if (end < 0) { + throw new RuntimeException("不存在的倒数第" + k + "个元素"); + } + HeroNode currNode = head.next; + for (int i = 0; i < end; i++) { + currNode = currNode.next; + } + return currNode; + } + + /** + * 单链表反转 + * 将原链表节点依次插入到反转链表的第一个位置 + */ + public void reverse() { + // 如果单链表中无节点或者只有一个节点 + if (head.next == null || head.next.next == null) { + return; + } + // currNode的作用:指向待插入反转链表节点的指针。遍历原单链表 + HeroNode currNode = head.next; + // nextNode的作用:暂存待插入反转链表节点的下一个节点 + HeroNode nextNode; + HeroNode reverseHead = new HeroNode(0, "", ""); + + while (currNode != null) { + // nextNode保存currNode.next,因为currNode.next本指向原链表, + // currNode.next = reverseHead.next会让currNode.next指向别的地方,导致找不到原链表 + nextNode = currNode.next; + currNode.next = reverseHead.next; + reverseHead.next = currNode; + // currNode每一次循环都会后移一个节点 + currNode = nextNode; + } + // 将原链表头节点指向反转链表头节点.next + head.next = reverseHead.next; + } + + /** + * 从尾到头打印单链表 + * + * @param + * @return void + */ + public void reverseList() { + HeroNode currNode = head.next; + Stack stack = new Stack<>(); + while (currNode != null) { + stack.add(currNode); + currNode = currNode.next; + } + int size = stack.size(); + for (int i = 0; i < size; i++) { + HeroNode node = stack.pop(); + System.out.printf("%d\t%s\t%s\t\n", node.no, node.name, node.nickName); + } + } + + /** + * 合并两个有序链表(合并后还有序) + * 方法一:遍历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节点开始遍历即可 + * @param singleLinkedList + * @return void + */ + public void mergeOrderLinkedList(SingleLinkedList singleLinkedList) { + // 方法一: + //HeroNode currNode = singleLinkedList.head.next; + //HeroNode nextNode; + //while (currNode != null) { + // nextNode = currNode.next; + // this.addByNoOrderIsEqual(currNode); + // currNode = nextNode; + //} + // 方法二: + // 2号链表 currNode1当前待合并节点 + HeroNode currNode2 = singleLinkedList.head.next; + // nextNode是currNode.next,防止2号链表后续节点丢失 + HeroNode nextNode2; + // 缓存刚插入节点的位置 + HeroNode currNodeChche2 = null; + + while (currNode2 != null) { + + nextNode2 = currNode2.next; + // 1号链表 + // 记录2号链表节点在1号链表节点插入的位置 + HeroNode tempNode1 = currNodeChche2; + if (tempNode1 == null) { + tempNode1 = this.head; + } + HeroNode preNode1; + boolean flag = true; //标识该节点是否插到最后一位 + while (true) { + if (tempNode1.next == null) { + break; + } + preNode1 = tempNode1; + tempNode1 = tempNode1.next; + if (currNode2.no <= tempNode1.no) { + // 1,3,4 nextNode.no=2 nextNode.next.no=3 2<3 可以添加 + // nextNode指向no=3节点 + currNode2.next = tempNode1; + // tempNode指向nextNode节点 + preNode1.next = currNode2; + flag = false; + break; + } + + } + if (flag) { + // 待插入节点no最大 + tempNode1.next = currNode2; + } + currNodeChche2 = currNode2; + // 存储2号链表的当前节点后移 + currNode2 = nextNode2; + } + } +} + +/** + * 单链表的节点 + */ +class HeroNode { + public int no; + public String name; + public String nickName; + public HeroNode next; + + public HeroNode(int no, String name, String nickName) { + this.no = no; + this.name = name; + this.nickName = nickName; + } + +} 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/atguigu/queue/ArrayQueueDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/ArrayQueueDemo.java new file mode 100644 index 00000000..5e924141 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/ArrayQueueDemo.java @@ -0,0 +1,104 @@ +package cn.lastwhisper.atguigu.queue; + +/** + * 数组实现队列 + * @author cn.lastwhisper + */ +public class ArrayQueueDemo { + + public static void main(String[] args) { + ArrayQueue arrayQueue = new ArrayQueue(3); + arrayQueue.addQueue(100); + arrayQueue.addQueue(200); + arrayQueue.addQueue(300); + System.out.println("=========显示队列信息========"); + arrayQueue.showQueue(); + System.out.println("=========显示队列头信息========"); + System.out.println(arrayQueue.headQueue()); + System.out.println("=========显示队列长度========"); + System.out.println(arrayQueue.size()); + System.out.println("=========取出队头数据========"); + System.out.println(arrayQueue.getQueue()); + System.out.println(arrayQueue.getQueue()); + System.out.println("=========显示队列长度========"); + System.out.println(arrayQueue.size()); + System.out.println("=========显示队列信息========"); + arrayQueue.showQueue(); + } +} + +class ArrayQueue { + private int maxSize; // 队列长度 + private int front; //指向头部 + private int rear; //指向尾部 + private int[] arr; //该数组存放元素 + + public ArrayQueue(int maxSize) { + this.maxSize = maxSize; + this.arr = new int[maxSize]; + this.front = -1; + this.rear = -1; + } + + // 入队前判断队列是否满了 + public void addQueue(int data) { + // 先判断队列是否满了 + if (isFull()) { + System.out.println("队列已满,不能添加数据"); + return; + } + rear++; + arr[rear] = data; + } + + // 出队前判断队列是否为空 + public int getQueue() { + if (isEmpty()) { + throw new RuntimeException("队列为空,不能取出数据"); + } + front++; + return arr[front]; + } + + // 查看队头元素 + public int headQueue() { + if (isEmpty()) { + throw new RuntimeException("队列为空,不能取出数据"); + } + return arr[front + 1]; + } + + // 判断队列是否为空 + public boolean isEmpty() { + return front == rear; + } + + // 判断队列是否满了 + public boolean isFull() { + return rear == maxSize - 1; + } + + // 显示队列情况 + public void showQueue() { + if (isEmpty()) { + System.out.println("空队列"); + } + //for (int i = front + 1; i < rear + 1; i++) { + // System.out.printf("%d\t", arr[i]); + //} + // 队列中元素个数 + int counter = size(); + // 队头 + int start = front; + while (counter > 0) { + start++; + System.out.printf("%d\t", arr[start]); + counter--; + } + System.out.println(); + } + + public int size() { + return rear - front; + } +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/CircleArrayQueueDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/CircleArrayQueueDemo.java new file mode 100644 index 00000000..bd6aa057 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/CircleArrayQueueDemo.java @@ -0,0 +1,107 @@ +package cn.lastwhisper.atguigu.queue; + +/** + * 数组实现循环队列 + * @author cn.lastwhisper + */ +public class CircleArrayQueueDemo { + + public static void main(String[] args) { + CircleArrayQueue arrayQueue = new CircleArrayQueue(5); + arrayQueue.addQueue(100); + arrayQueue.addQueue(200); + arrayQueue.addQueue(300); + arrayQueue.addQueue(400); + System.out.println("=========显示队列信息========"); + arrayQueue.showQueue(); + System.out.println("=========显示队列头信息========"); + System.out.println(arrayQueue.headQueue()); + System.out.println("=========显示队列长度========"); + System.out.println(arrayQueue.size()); + System.out.println("=========取出队头数据========"); + System.out.println(arrayQueue.getQueue()); + System.out.println(arrayQueue.getQueue()); + System.out.println("=========显示队列长度========"); + System.out.println(arrayQueue.size()); + System.out.println("=========向循环队列添加元素 500,600========"); + arrayQueue.addQueue(500); + arrayQueue.addQueue(600); + System.out.println("=========显示队列信息========"); + arrayQueue.showQueue(); + } +} + +class CircleArrayQueue { + + private int maxSize; // 队列最大长度 + private int front; // 队头指针 + private int rear; // 队尾指针 + private int[] arr; // 队列中的数据 + + public CircleArrayQueue(int maxSize) { + this.maxSize = maxSize; + this.arr = new int[maxSize]; + } + + // 入队,先添加数据再移动尾指针 + public void addQueue(int data) { + // 先判断队列是否满了 + if (isFull()) { + System.out.println("队列已满,不能添加数据"); + return; + } + // maxSize=4,rear=3,添加一个元素后rear=0 + rear = (rear + 1) % maxSize; + arr[rear] = data; + } + + // 出队,先获取数据再移动头指针 + public int getQueue() { + // 出队前判断队列是否为空 + if (isEmpty()) { + throw new RuntimeException("队列为空,不能取出数据"); + } + front = (front + 1) % maxSize; + int data = arr[front]; + return data; + } + + // 查看队头元素 + public int headQueue() { + if (isEmpty()) { + throw new RuntimeException("队列为空,不能取出数据"); + } + return arr[front + 1]; + } + + // 判断队列是否为空 + public boolean isEmpty() { + return front == rear; + } + + // 判断队列是否满了 + public boolean isFull() { + return (rear + 1) % maxSize == front; + } + + // 显示队列情况 + public void showQueue() { + if (isEmpty()) { + System.out.println("空队列"); + } + // 队列中元素个数 + int counter = size(); + // 队头 + int start = front; + while (counter > 0) { + start = (start + 1) % maxSize; + System.out.printf("%d\t", arr[start]); + counter--; + } + System.out.println(); + } + + public int size() { + return (rear + maxSize - front) % maxSize; + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Maze.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Maze.java new file mode 100644 index 00000000..e496578b --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Maze.java @@ -0,0 +1,87 @@ +package cn.lastwhisper.atguigu.recursion; + +/** + * 递归解决迷宫问题 + * @author cn.lastwhisper + */ +public class Maze { + public static void main(String[] args) { + // 1、初始化迷宫 8(row)7(column) + int map[][] = new int[8][7]; + // map.length——》row.length,map[0].length——》 column.length + // 左右边界设为1 + for (int i = 0; i < map.length; i++) { + map[i][0] = 1; + map[i][map[0].length - 1] = 1; + } + // 上下边界置为1 + for (int i = 0; i < map[0].length; i++) { + map[0][i] = 1; + map[map.length - 1][i] = 1; + } + // 设置迷宫 + map[3][1] = 1; + map[3][2] = 1; + + //map[3][1] = 1; + //map[3][2] = 1; + //map[4][3] = 1; + //map[3][4] = 1; + //map[2][4] = 1; + for (int i = 0; i < map.length; i++) { + for (int j = 0; j < map[0].length; j++) { + System.out.printf("%d ", map[i][j]); + } + System.out.println(); + } + System.out.println("=============走出迷宫============="); + getWay(map, 1, 1); + for (int i = 0; i < map.length; i++) { + for (int j = 0; j < map[0].length; j++) { + System.out.printf("%d ", map[i][j]); + } + System.out.println(); + } + } + + /** + * map表示地图、i,j表示从地图的某个位置开始出发、map[6][5]为终点 + * 约定:0表示没有走过、1表示不通、2表示通路、3表示已经走过无法走通 + * 走迷宫策略:下——》右——》上——》左,如果该点走不通再递归回溯 + * @return boolean + */ + public static boolean getWay(int[][] map, int i, int j) { + // 找到终点 + if (map[6][5] == 2) { + return true; + } else { + // 0表示没有走过、1表示不通、2表示通路、3表示已经走过无法走通 + if (map[i][j] == 0) { + // 尝试 下——》右——》上——》左 + map[i][j] = 2; + if (getWay(map, i + 1, j)) { + //下 + return true; + } else if (getWay(map, i, j + 1)) { + //右 + return true; + } else if (getWay(map, i - 1, j)) { + //上 + return true; + } else if (getWay(map, i, j - 1)) { + //左 + return true; + } else { + // 下——》右——》上——》左走不通 + map[i][j] = 3; + return false; + } + } else { + // 此路不通或已走过 + return false; + } + } + } + + +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Queue8.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Queue8.java new file mode 100644 index 00000000..cec867c9 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Queue8.java @@ -0,0 +1,77 @@ +package cn.lastwhisper.atguigu.recursion; + +/** + * 递归解决八皇后问题 + * @author cn.lastwhisper + */ +public class Queue8 { + + static int count = 0; + static int judgeCount = 0; + // 定义一个max表示有多少个皇后 + private int max = 8; + // 定义一个数组保存皇后解法 arr[8] = { 0, 4, 7, 5, 2, 6, 1, 3} + // arr的意义:(index:下标、val:数组取某下标时数组对应的值) + // (1)arr的index+1表示第几个皇后(一行一个皇后)。 + // (2)arr的index对应数组的val表示第index+1个皇后放在第val+1列。 + // 示例:arr的index=1时表示第2个皇后,arr[index]=val=4表示第2个皇后放在第5列 + // 一句话:row=下标+1;column=arr[下标]+1 + int[] arr = new int[max]; + + public static void main(String[] args) { + Queue8 queue8 = new Queue8(); + // 测试judge方法是否正确 + //queue8.arr[0] = 0; //第一皇后在 0,0 + //queue8.arr[1] = 1; //第二个皇后在 1,1 + //System.out.println(queue8.judge(1)); + + // 测试8皇后是否正确 ; + queue8.check(0); + System.out.printf("一共有%d解法\n", count); + System.out.printf("一共判断冲突的次数%d次", judgeCount); // 1.5w + } + + // 放置第index个皇后 + public void check(int index) { + // index从0开始 + if (index == max) { + print(); + return; + } + // 每次一check的递归都会重新循环 + for (int i = 0; i < max; i++) { + // 将第index个皇后,放置第i+1列。 + arr[index] = i; + // 判断当前放置的位置与之前的皇后是否冲突 + if (judge(index)) { + this.check(index + 1); + } + } + } + + // 放置第index(n=index+1)个皇后之后,检测是否和前面已经摆放的皇后冲突 + private boolean judge(int n) { + judgeCount++; + for (int i = 0; i < n; i++) { + // 同一列:arr[i] == arr[n];column=arr[下标]+1 + // 同一斜线:Math.abs(n - i) == Math.abs(arr[n] - arr[i]),判断第n个皇后是否和第i个皇后在同一斜线 + // 详解:i=0 arr[i]=0,第1个皇后放在第1列;n=1 arr[n]=1,第2个皇后放在第2列 + // Math.abs(1 - 0)==Math.abs(arr[1] - arr[0])) + // 下标之差等于对应数组数值之差说明在同一对角线上(下标对应row、数组数值对应column) + // 同一行:由arr数组的意义来看不可能存在同一行 + if (arr[i] == arr[n] || Math.abs(n - i) == Math.abs(arr[n] - arr[i])) { + return false; + } + } + return true; + } + + //写一个方法,可以将皇后摆放的位置输出 + private void print() { + count++; + for (int i = 0; i < arr.length; i++) { + System.out.print(arr[i] + " "); + } + System.out.println(); + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Recursion.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Recursion.java new file mode 100644 index 00000000..3d253071 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Recursion.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.atguigu.recursion; + +/** + * 递归通俗解释: + * 1)、https://www.zhihu.com/question/20507130/answer/31826402 + * 坐在第几排——》坐在电影院里,你想知道自己坐在第几排,于是你问前面一排的A【你坐在那一排】,这样A的排数+1你就知道自己在第几排了。 + * A也不知道自己坐在那一排,于是A问他前一排的B【你坐在那一排】,B也不知道自己坐在那一排,于是B...,一直问到第一排的人, + * 递归结束,开始回溯,最后大家都知道自己坐在那一排了。 + * 2)、https://www.zhihu.com/question/20507130/answer/52759136 + * 查字典——》查一个词,发现这个词的解释中某个词仍不懂,于是查第二个词,第二个词的解释中某个词仍不懂,于是查第三个词 + * ,直到有一个词你明白了,递归结束,开始回溯,懂了第三个词,懂了第二个词,懂了查的这个词。 + * @author cn.lastwhisper + */ +public class Recursion { + public static void main(String[] args) { + System.out.println(fun(5)); + } + + public static int fun(int n) { + if (n == 1) { + return 1; + } else { + return fun(n - 1) * n; + } + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/BinarySearch.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/BinarySearch.java new file mode 100644 index 00000000..c180a504 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/BinarySearch.java @@ -0,0 +1,190 @@ +package cn.lastwhisper.atguigu.search; + +import cn.lastwhisper.util.ArrayUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author cn.lastwhisper + */ +public class BinarySearch { + private static int count = 0; + + public static void main(String[] args) { + // 无重复值 + //int[] arr = {1, 8, 10, 89, 1000, 1234}; + + int[] arr = ArrayUtil.generateArrByOrder(100); + int i = binarySearch1(arr, 35); + System.out.println("查找次数:"+count); + //int i = binarySearch2(arr, 0, arr.length - 1, 11); + if (i == -1) { + System.out.println("没有找到"); + } else { + System.out.printf("找到了!下标为:%d,数值为:%d", i, arr[i]); + } + // 有重复值 + //int[] arr = {1, 1, 1, 1, 10, 89, 1000, 1234}; + //int[] arr = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1,}; + //List indexs = binarySearch3(arr, 1); + //List indexs = binarySearch4(arr, 0, arr.length - 1, 1); + //for (Integer integer : indexs) { + // System.out.println(integer); + //} + } + + /** + * 二分搜索(非递归) + * Xae=ro/iA1li + * @param arr + * @param target + * @return int + */ + public static int binarySearch1(int[] arr, int target) { + if (target < arr[0] || target > arr[arr.length - 1]) { + return -1; + } + int left = 0; //[0..mid] [mid+1...arr.length-1] + int right = arr.length - 1; + int mid = (left + right) / 2; + while (left < right) { + if (target == arr[mid]) { + return mid; + } else if (target > arr[mid]) { + // 在mid的右边找 + left = mid + 1; + mid = (left + right) / 2; + } else { + right = mid - 1; + mid = (left + right) / 2; + } + count++; + } + return -1; + } + + /** + * 二分搜索(递归) + * + * @param arr + * @param left + * @param right + * @param target + * @return int + */ + public static int binarySearch2(int[] arr, int left, int right, int target) { + if (left > right || target < arr[0] || target > arr[arr.length - 1]) { + return -1; + } + int mid = left + (right - left) / 2; + if (target == arr[mid]) { + return mid; + } else if (target > arr[mid]) { + // 在mid的右边找 + return binarySearch2(arr, mid + 1, right, target); + } else { + // 在mid的左边找 + return binarySearch2(arr, left, mid - 1, target); + } + } + + /** + * 二分搜索(非递归,可重复值) + * + * @param arr + * @param target + * @return int + */ + public static List binarySearch3(int[] arr, int target) { + int left = 0; //[0..mid] [mid+1...arr.length-1] + int right = arr.length - 1; + int mid = (left + right) / 2; + List indexs = new ArrayList<>(); + while (left < right) { + if (target == arr[mid]) { + int midTemp = mid; + + while (midTemp >= left && arr[midTemp] == target) { + indexs.add(midTemp); + midTemp--; + } + // 因为[left...mid]已经被扫描过了,所以mid先加,接着扫描[mid+1...right] + mid++; + while (mid <= right && arr[mid] == target) { + indexs.add(mid); + mid++; + } + break; + } else if (target > arr[mid]) { + // 在mid的右边找 + left = mid + 1; + mid = (left + right) / 2; + } else { + right = mid - 1; + mid = (left + right) / 2; + } + } + return indexs; + } + + /** + * 二分搜索(递归,可重复值) + * + * @param arr + * @param left + * @param right + * @param findVal + * @return int + */ + public static List binarySearch4(int[] arr, int left, int right, int findVal) { + + System.out.println("hello~"); + // 当 left > right 时,说明递归整个数组,但是没有找到 + if (left > right) { + return new ArrayList(); + } + int mid = left + (right - left) / 2; + int midVal = arr[mid]; + + if (findVal > midVal) { // 向 右递归 + return binarySearch4(arr, mid + 1, right, findVal); + } else if (findVal < midVal) { // 向左递归 + return binarySearch4(arr, left, mid - 1, findVal); + } else { +// * 思路分析 +// * 1. 在找到mid 索引值,不要马上返回 +// * 2. 向mid 索引值的左边扫描,将所有满足 1000, 的元素的下标,加入到集合ArrayList +// * 3. 向mid 索引值的右边扫描,将所有满足 1000, 的元素的下标,加入到集合ArrayList +// * 4. 将Arraylist返回 + + List resIndexlist = new ArrayList(); + //向mid 索引值的左边扫描,将所有满足 1000, 的元素的下标,加入到集合ArrayList + int temp = mid - 1; + while (true) { + if (temp < 0 || arr[temp] != findVal) {//退出 + break; + } + //否则,就temp 放入到 resIndexlist + resIndexlist.add(temp); + temp -= 1; //temp左移 + } + resIndexlist.add(mid); // + + //向mid 索引值的右边扫描,将所有满足 1000, 的元素的下标,加入到集合ArrayList + temp = mid + 1; + while (true) { + if (temp > arr.length - 1 || arr[temp] != findVal) {//退出 + break; + } + //否则,就temp 放入到 resIndexlist + resIndexlist.add(temp); + temp += 1; //temp右移 + } + + return resIndexlist; + } + + } + +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/FibonacciSearch.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/FibonacciSearch.java new file mode 100644 index 00000000..c9dcfd56 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/FibonacciSearch.java @@ -0,0 +1,41 @@ +package cn.lastwhisper.atguigu.search; + +import cn.lastwhisper.util.ArrayUtil; + +/** + * + * @author cn.lastwhisper + */ +public class FibonacciSearch { + private static int count = 0; + + public static void main(String[] args) { + int[] arr = ArrayUtil.generateArrByOrder(100); + //int[] arr = {1, 1, 1, 1, 10, 89, 1000, 1234}; + System.out.println(fibonacciSearch(arr, 37)); + System.out.println("查找次数:" + count); + } + + //因为后面我们mid=low+F(k-1)-1,需要使用到斐波那契数列,因此我们需要先获取到一个斐波那契数列 + //非递归方法得到一个斐波那契数列 + public static int[] fib() { + int[] f = new int[20]; + f[0] = 1; + f[1] = 1; + for (int i = 2; i < 20; i++) { + f[i] = f[i - 1] + f[i - 2]; + } + return f; + } + + /** + * 斐波那契(黄金分割法)查找(递归) + * + * @param arr + * @param target + * @return int + */ + public static int fibonacciSearch(int[] arr, int target) { + return 0; + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/InsertValueSearch.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/InsertValueSearch.java new file mode 100644 index 00000000..904e621f --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/InsertValueSearch.java @@ -0,0 +1,43 @@ +package cn.lastwhisper.atguigu.search; + +import cn.lastwhisper.util.ArrayUtil; + +/** + * + * @author cn.lastwhisper + */ +public class InsertValueSearch { + private static int count = 0; + public static void main(String[] args) { + int[] arr = ArrayUtil.generateArrByOrder(100); + //int[] arr = {1, 1, 1, 1, 10, 89, 1000, 1234}; + System.out.println(insertValueSearch(arr, 0, arr.length - 1, 37)); + System.out.println("查找次数:"+count); + } + + /** + * 插值查找(递归) + * + * @param arr + * @param left + * @param right + * @param target + * @return int + */ + public static int insertValueSearch(int[] arr, int left, int right, int target) { + count++; + // 必要条件 + if (left > right || target < arr[0] || target > arr[arr.length - 1]) { + return -1; + } + // 自适应写法 + int mid = left + (right - left) * (target - arr[left]) / (arr[right] - arr[left]); + if (target > arr[mid]) { + return insertValueSearch(arr, mid + 1, right, target); + } else if (target < arr[mid]) { + return insertValueSearch(arr, left, mid - 1, target); + } else { + return mid; + } + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/SeqSearch.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/SeqSearch.java new file mode 100644 index 00000000..31f1993c --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/SeqSearch.java @@ -0,0 +1,33 @@ +package cn.lastwhisper.atguigu.search; + +/** + * @author cn.lastwhisper + */ +public class SeqSearch { + + public static void main(String[] args) { + int[] arr = {1, 8, 10, 89, 1000, 1234}; + int i = orderSearch(arr, 10); + if (i == -1) { + System.out.println("没有找到"); + } else { + System.out.printf("找到了!下标为:%d,数值为:%d", i, arr[i]); + } + } + + /** + * 线性查找 + * + * @param + * @return int 数组下标 + */ + public static int orderSearch(int[] arr, int target) { + for (int i = 0; i < arr.length; i++) { + if (arr[i] == target) { + return i; + } + } + return -1; + } + +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/DubbleSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/DubbleSort.java new file mode 100644 index 00000000..fdfc3682 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/DubbleSort.java @@ -0,0 +1,53 @@ +package cn.lastwhisper.atguigu.sort; + +import cn.lastwhisper.util.ArrayUtil; + +/** + * @author cn.lastwhisper + */ +public class DubbleSort { + public static void main(String[] args) { + //int[] arr = {3, 9, -1, 10, -2}; + //int[] arr = {1, 2, 3, 4, 5, 6, 7}; + int[] arr = ArrayUtil.generateArrByRandom(100000); + // 计算耗时 + long start = System.currentTimeMillis(); + bubbleSort(arr); + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start) + " ms"); + } + + /** + * 冒泡排序O(n^2) + * + * @param arr + * @return void + */ + public static void bubbleSort(int[] arr) { + int temp; + // 标识是否发生交换,默认不交换;即默认数组是升序 + boolean flag = false; + // 外循环是当前已经找到最大值得个数 + for (int i = 0; i < arr.length; i++) { + // 内循环进行冒泡,每循环一次arr最后i位数就是最大的数,可以不进行比较,即arr.length-i。 + // 10个数两两相邻比较,需要比较9次,即arr.length - 1 + // 所以内循环为:arr.length - 1 - i + for (int j = 0; j < arr.length - 1 - i; j++) { + if (arr[j] > arr[j + 1]) { + flag = true; + temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + //System.out.printf("第%d趟排序后的数组", i + 1); + //System.out.println(Arrays.toString(arr)); + // 内循环未发生交换,说明数组目前已经有序,直接退出外循环 + if (!flag) { + break; + } else { + flag = false;//重置 + } + } + } +} 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/atguigu/sort/TimeComplexity.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/TimeComplexity.java new file mode 100644 index 00000000..36734634 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/TimeComplexity.java @@ -0,0 +1,58 @@ +package cn.lastwhisper.atguigu.sort; + +/** + * 时间复杂度举例 + * @author cn.lastwhisper + */ +public class TimeComplexity { + + public static void main(String[] args){ + new TimeComplexity().n2(5); + } + // O(1) + public void o1() { + int x = 1, s; + for (int i = 0; i < 10000; i++) { + x++; + s = 0; + } + } + + // O(logn) + public void logn(int n) { + int i = 1; + while (i < n) { + i = i * 2; + } + } + + // O(n) + public void n(int n) { + int j = 0; + for (int i = 0; i < n; i++) { + j++; + } + } + + // O(nlogn) + public void nlogn(int n) { + for (int m = 0; m < n; m++) { + int i = 1; + while (i < n) { + i = i * 2; + } + } + } + + // O(n^2) + public void n2(int n) { + int k = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + k++; + } + } + } + + +} 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/atguigu/sparsematrix/BestSpmatrix.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/BestSpmatrix.java new file mode 100644 index 00000000..e1fd05b9 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/BestSpmatrix.java @@ -0,0 +1,81 @@ +package cn.lastwhisper.atguigu.sparsematrix; + +/** + * @author cn.lastwhisper + */ +public class BestSpmatrix { + /** + * 三元组,保存有效元素的信息 + */ + private static class Node { + int i, j; // 三元组的行、列坐标 + int v; // 三元组的值 + + public Node(int i, int j, int v) { + this.i = i; + this.j = j; + this.v = v; + } + } + + private static class Spmatrix { + int rows, cols;//稀疏矩阵的行、列数 + int terms; //稀疏矩阵的非零元素个数 + Node[] node;//存放稀疏矩阵的三元组表 + + public Spmatrix(int rows, int cols, int terms, Node[] node) { + this.rows = rows; + this.cols = cols; + this.terms = terms; + this.node = node; + } + } + + public static void main(String[] args) { + // 准备一个稀疏矩阵 + int rowNum = 11; + int columnNum = 11; + int[][] chessMatrix = new int[rowNum][columnNum]; + chessMatrix[1][2] = 1; + chessMatrix[2][3] = 2; + + // 压缩 + int sum = 0; + for (int i = 0; i < rowNum; i++) { + for (int j = 0; j < columnNum; j++) { + if (chessMatrix[i][j] != 0) { + sum++; + } + } + } + Spmatrix spmatrix = new Spmatrix(rowNum, columnNum, sum, new Node[sum]); + + int index = 0; + for (int i = 0; i < rowNum; i++) { + for (int j = 0; j < columnNum; j++) { + if (chessMatrix[i][j] != 0) { + spmatrix.node[index++] = new Node(i, j, chessMatrix[i][j]); + } + } + } + + for (int i = 0; i < spmatrix.node.length; i++) { + System.out.printf("%d\t%d\t%d\t\n", spmatrix.node[i].i, spmatrix.node[i].j, spmatrix.node[i].v); + } + + // 还原 + // 取出第一行元素的行、列维度,创建稀疏矩阵 + int[][] matrix = new int[spmatrix.rows][spmatrix.cols]; + // 追个取出剩余行并还原稀疏矩阵 + for (int i = 0; i < spmatrix.node.length; i++) { + matrix[spmatrix.node[i].i][spmatrix.node[i].j] = spmatrix.node[i].v; + } + + for (int i = 0; i < rowNum; i++) { + for (int j = 0; j < columnNum; j++) { + System.out.printf("%d\t", matrix[i][j]); + } + System.out.println(); + } + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/SparseMatrix.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/SparseMatrix.java new file mode 100644 index 00000000..50f30722 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/SparseMatrix.java @@ -0,0 +1,90 @@ +package cn.lastwhisper.atguigu.sparsematrix; + +/** + * 稀疏矩阵压缩与还原 + * @author cn.lastwhisper + */ +public class SparseMatrix { + + + /** + * 压缩稀疏矩阵 + * 稀疏数组第一行保存数组的行、列的维度以及有效元素的个数 + * 其余行保存有效数据行、列的坐标以及有效数据本身 + * + * @param sparseMatrix 稀疏矩阵 + * @param rows 行维度 + * @param cols 列维度 + * @return int[][] + */ + private int[][] compress(int[][] sparseMatrix, int rows, int cols) { + // 计算有效元素的个数 + int sum = 0; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (sparseMatrix[i][j] != 0) { + sum++; + } + } + } + // 三元组表 + int[][] tripleTable = new int[sum + 1][3]; + tripleTable[0][0] = rows; + tripleTable[0][1] = cols; + tripleTable[0][2] = sum; + int index = 0; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (sparseMatrix[i][j] != 0) { + index++; + tripleTable[index][0] = i; + tripleTable[index][1] = j; + tripleTable[index][2] = sparseMatrix[i][j]; + } + } + } + return tripleTable; + } + + /** + * 还原稀疏矩阵 + * + * @param tripleTable + * @return int[][] + */ + private int[][] recovery(int[][] tripleTable) { + // 取出第一行元素的行、列维度,创建稀疏矩阵 + int[][] matrix = new int[tripleTable[0][0]][tripleTable[0][1]]; + // 追个取出剩余行并还原稀疏矩阵 + for (int i = 1; i < tripleTable.length; i++) { + matrix[tripleTable[i][0]][tripleTable[i][1]] = tripleTable[i][2]; + } + return matrix; + } + + public static void main(String[] args) { + // 准备一个稀疏矩阵 + int rowNum = 11; + int columnNum = 11; + int[][] chessMatrix = new int[rowNum][columnNum]; + chessMatrix[1][2] = 1; + chessMatrix[2][3] = 2; + // 压缩 + SparseMatrix sparseMatrix = new SparseMatrix(); + int[][] tripleTable = sparseMatrix.compress(chessMatrix, rowNum, columnNum); + + for (int i = 0; i < tripleTable.length; i++) { + System.out.printf("%d\t%d\t%d\t\n", tripleTable[i][0], tripleTable[i][1], tripleTable[i][2]); + } + // 还原 + chessMatrix = sparseMatrix.recovery(tripleTable); + + for (int i = 0; i < rowNum; i++) { + for (int j = 0; j < columnNum; j++) { + System.out.printf("%d\t", chessMatrix[i][j]); + } + System.out.println(); + } + + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/ArrayStackDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/ArrayStackDemo.java new file mode 100644 index 00000000..5a20dc99 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/ArrayStackDemo.java @@ -0,0 +1,74 @@ +package cn.lastwhisper.atguigu.stack; + +/** + * @author cn.lastwhisper + */ +public class ArrayStackDemo { + public static void main(String[] args) { + ArrayStack arrayStack = new ArrayStack(4); + arrayStack.push(1); + arrayStack.push(2); + arrayStack.push(3); + arrayStack.push(4); + arrayStack.push(5); + System.out.println("当前栈的容量:"+arrayStack.size()); + arrayStack.push(6); + System.out.println(arrayStack.pop()); + System.out.println(arrayStack.pop()); + System.out.println(arrayStack.pop()); + System.out.println(arrayStack.pop()); + System.out.println("当前栈的容量:"+arrayStack.size()); + } +} + +class ArrayStack { + private int[] arr; + private int n = 0; + + public ArrayStack(int initialCapacity) { + this.arr = new int[initialCapacity]; + } + // + // 栈满 + + // 栈空 + public boolean isEmpty() { + return n == 0; + } + + // 入栈 + public void push(int data) { + if (n > 0 && n == arr.length) { + resize(2 * n); + } + arr[n++] = data; + } + + // 出栈 + public int pop() { + if (isEmpty()) { + return -1; + } + if (n > 0 && n == (arr.length / 4)) { + resize(n / 2); + } + return arr[--n]; + } + // 查看栈顶元素 + public int peek(){ + int temp = n; + return arr[--temp]; + } + + // size + public int size() { + return n; + } + + // resize + public void resize(int maxSize) { + int[] newArr = new int[maxSize]; + 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/atguigu/stack/InCalculator.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/InCalculator.java new file mode 100644 index 00000000..1288660c --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/InCalculator.java @@ -0,0 +1,188 @@ +package cn.lastwhisper.atguigu.stack; + +/** + * 中缀表达式 + * @author cn.lastwhisper + */ +public class InCalculator { + public static void main(String[] args) { + // 符号栈、数值栈 + CalcArrayStack operStack = new CalcArrayStack(10); + CalcArrayStack numStack = new CalcArrayStack(10); + // 计算结果、数值1、数值2、运算符、当前值 + int res = 0; + int num1 = 0; + int num2 = 0; + int oper = 0; + int ch = 0; + String keepNum = ""; + // index辅助遍历表达式 + int index = 0; + // 中缀表达式 + //String expression = "7*2*2-5+1-5+3-4"; + String expression = "30+2*6-2"; + // 解析中缀表达式 + while (index != expression.length()) { + // 1、通过index遍历表达式 + ch = expression.substring(index, index + 1).charAt(0); + if (operStack.isOper(ch)) { + // 2、如果是oper进入符号栈,入符号栈分为两种情况 + // (1)、当前符号栈为空,直接入栈 + // (2)、当前符号栈不为空,peek出栈顶运算符,进行运算符优先级比较 + // 如果当前oper优先级大于栈顶运算符,直接入栈 + // 如果小于,弹出符号栈栈顶运算符,弹出两个数值,进行运算并将运算结果push数值栈,再将oper压入符号栈 + if (operStack.isEmpty()) { + operStack.push(ch); + } else { + oper = operStack.peek(); + if (operStack.priority(ch) > operStack.priority(oper)) { + operStack.push(ch); + } else { + oper = operStack.pop(); + num1 = numStack.pop(); + num2 = numStack.pop(); + res = numStack.calc(num1, num2, oper); + numStack.push(res); + operStack.push(ch); + } + } + } else { + // 3、如果是num进入数值栈 + //numStack.push(ch - 48); + // 处理多位数'1'+'5'——》15 + keepNum += ch - 48; + // ch是否是最后一个字符 + if (index == expression.length() - 1) { + numStack.push(Integer.parseInt(keepNum)); + } else { + // 如果后一位是运算符,则将当前keepNum入栈 + if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) { + numStack.push(Integer.parseInt(keepNum)); + // 每次清空多位数 + keepNum = ""; + } + } + } + index++; + } + // 4、解析完表达式后,弹出符号栈、数值栈对应的运算符和数值进行运算,再将结果入栈 + // 重复第四步直至数值栈中只剩一个运算结果 + while (!operStack.isEmpty()) { + oper = operStack.pop(); + num1 = numStack.pop(); + num2 = numStack.pop(); + res = numStack.calc(num1, num2, oper); + numStack.push(res); + } + System.out.printf("%s=%d", expression, numStack.pop()); + } +} + + +class CalcArrayStack { + private int[] arr; + private int n = 0; + + public CalcArrayStack(int initialCapacity) { + this.arr = new int[initialCapacity]; + } + // 栈满 + + // 入栈 + public void push(int data) { + if (n > 0 && n == arr.length) { + resize(2 * arr.length); + } + arr[n++] = data; + } + + // 出栈 + public int pop() { + if (isEmpty()) { + throw new RuntimeException("栈空"); + } + if (n > 0 && n == (arr.length / 4)) { + resize(arr.length / 2); + } + return arr[--n]; + } + + /** + * 显示栈中情况 + */ + public void list() { + for (int i = n; i > 0; i--) { + System.out.printf("%d\t", arr[i]); + } + } + + // 栈空 + public boolean isEmpty() { + return n == 0; + } + + // 查看栈顶元素 + public int peek() { + if (isEmpty()) { + throw new RuntimeException("栈空"); + } + int temp = n; + return arr[--temp]; + } + + // size + public int size() { + return n; + } + + // resize + public void resize(int maxSize) { + int[] newArr = new int[maxSize]; + for (int i = 0; i < size(); i++) { + newArr[i] = arr[i]; + } + this.arr = newArr; + } + + // 返回运算符的优先级 + public int priority(int oper) { + if (oper == '*' || oper == '/') { + return 1; + } else if (oper == '+' || oper == '-') { + return 0; + } else { + return -1; + } + } + + // 判断是不是一个运算符 + public boolean isOper(int oper) { + return oper == '*' || oper == '/' || oper == '+' || oper == '-'; + } + + // 计算方法接收两个数和一个运算符 + public int calc(int num1, int num2, int oper) { + int res = 0; + switch (oper) { + case '*': + res = num1 * num2; + break; + case '/': + if (num2 != 0) { + res = num1 / num2; + } else { + throw new RuntimeException("非法的除零运算"); + } + break; + case '+': + res = num1 + num2; + break; + case '-': + res = num2 - num1; + break; + default: + break; + } + return res; + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/SuCalculator.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/SuCalculator.java new file mode 100644 index 00000000..18d7afa0 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/SuCalculator.java @@ -0,0 +1,226 @@ +package cn.lastwhisper.atguigu.stack; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * 后缀表达式 + * @author cn.lastwhisper + */ +public class SuCalculator { + public static void main(String[] args) { + // 1+((2+3)*4)-5 ——》 + String infixExpression = "111+((2+3)*4)-5"; + //String suffixExpression = ""; + // 中缀String串转中缀List "1+((2+3)*4)-5" ——》[1,+,(,(,2,+,3,),*,4,),-,5] + //List infixList = infixStrConvertInfixList(infixExpression); + //for (int i = 0; i < infixList.size(); i++) { + // String str = infixList.get(i); + // if (i == infixList.size() - 1) { + // System.out.print(str); + // } else { + // System.out.print(str + " "); + // } + //} + // 前缀表达式转为后缀表达式 "1+((2+3)*4)-5"——》"1 2 3 + 4 * + 5 -" + String suffixExpression = infixConverSufix(infixExpression); + System.out.println("前缀:" + infixExpression); + System.out.println("后缀:" + suffixExpression); + // 后缀表达式解析计算 + int result = calcSufix(suffixExpression); + System.out.println("计算结果:" + result); + } + + /** + * 中缀表达式转后缀表达式 + * + * @param infixExpression + * @return java.lang.String + */ + public static String infixConverSufix(String infixExpression) { + List infixExpressionList = infixStrConvertInfixList(infixExpression); + // 1、初始化两个栈,s1运算符栈,s2中间结果栈 + Stack s1 = new Stack<>(); + //说明:因为s2 这个栈,在整个转换过程中,没有pop操作,而且后面我们还需要逆序输出 + //因此比较麻烦,这里可以不用 Stack 直接使用 List s2 + Stack s2 = new Stack<>(); + // 2、循环遍历前缀表达式 + for (String infix : infixExpressionList) { + // 3、遇到运算符infix,与s1栈顶运算符比较优先级 ")">"*"="/">"+"="-">"(" + // (1)、如果s1栈顶是空,或者是"(",直接入栈 + // (2)、如果infix优先级大于s1栈顶运算符,直接入栈 + // (3)、如果infix优先级小于或等同于s1栈顶运算符,将s1栈顶运算符压入s2栈。再将oper重复(1)(2)(3) + if (isOper(infix)) { + boolean flag = true; + while (flag) { + // .trim()是因为,3(3)会将s1栈顶运算符压入s2栈,而s1栈中元素都加上空格了 + if (s1.isEmpty() || s1.peek().trim().equals("(")) { + s1.push(infix + " "); + flag = false; + } else if (priority(infix) > priority(s1.peek().trim())) { + s1.push(infix + " "); + flag = false; + } else if (priority(infix) <= priority(s1.peek().trim())) { + s2.push(s1.pop()); + } + } + // 4、遇到括号 + } else if (infix.equals("(")) { + // (1)、左括号直接入s1栈 + s1.push(infix); + } else if (infix.equals(")")) { + // (2)、右括号。依次弹出s1栈顶运算符,压入s2中,直到遇到左括号位置,此时将左括号丢弃 + //while (!s1.peek().equals(")")) { + // s2.push(s1.pop() + " "); + //} + while (true) { + s2.push(s1.pop().trim() + " "); + if (s1.peek().equals("(")) { + break; + } + } + s1.pop(); + } else if (infix.matches("\\d+")) { + // 5、遇到数字,直接入s2 + s2.push(infix + " "); + } + + } + // 6、将s1剩余的运算符压入s2中 + while (!s1.empty()) { + s2.push(s1.pop().trim()); + } + // 7、依次弹出s2中的元素,即后缀表达式 + StringBuffer sb = new StringBuffer(); + for (String s : s2) { + sb.append(s); + } + return sb.toString().trim(); + } + + /** + * 中缀表达式String转中缀表达式Lsit + * + * @param infixExpression + * @return java.array.List + */ + public static List infixStrConvertInfixList(String infixExpression) { + List infixList = new ArrayList<>(); + // 记录多位数 + String keepNum = ""; + for (int i = 0; i < infixExpression.length(); i++) { + String subStr = infixExpression.substring(i, i + 1); + if (isOper(subStr)) { + // 运算符 + infixList.add(subStr); + } else if (subStr.equals("(") || subStr.equals(")")) { + infixList.add(subStr); + } else { + // 数字 + keepNum += subStr; + // 前缀表达式的最后一个字符 + if (i == infixExpression.length() - 1) { + infixList.add(keepNum); + } else { + // 非前缀表达式的最后一个字符 + // 后一位是字符 + String subnextStr = infixExpression.substring(i + 1, i + 2); + if (isOper(subnextStr) || subnextStr.equals("(") || subnextStr.equals(")")) { + infixList.add(keepNum); + keepNum = ""; + } + } + } + + } + return infixList; + } + + /** + * 解析并计算后缀表达式 + * + * @param suffixExpression + * @return int + */ + public static int calcSufix(String suffixExpression) { + String[] expressions = suffixExpression.split(" "); + Stack stack = new Stack<>(); + // 1、遍历表达式 + for (int i = 0; i < expressions.length; i++) { + String str = expressions[i]; + if (isOper(str)) { + // 2、遇到运算符,弹出栈顶两个数,进行运算入栈 + Integer num1 = stack.pop(); + Integer num2 = stack.pop(); + int sum = calc(num1, num2, str); + stack.push(sum); + } else { + // 3、将数字push入栈 + stack.push(Integer.valueOf(str)); + } + } + return stack.pop(); + } + + /** + * 判断是否是运算符 + * + * @param oper + * @return boolean + */ + public static boolean isOper(String oper) { + return "*".equals(oper) || "/".equals(oper) || "+".equals(oper) || "-".equals(oper); + } + + /** + * 计算两个num + * + * @param num1 + * @param num2 + * @param oper + * @return int + */ + public static int calc(int num1, int num2, String oper) { + int res = 0; + switch (oper) { + case "*": + res = num1 * num2; + break; + case "/": + res = num1 / num2; + break; + case "+": + res = num1 + num2; + break; + case "-": + res = num2 - num1; + break; + default: + break; + } + return res; + } + + /** + * 计算运算符的优先级 + * ")">"*"="/">"+"="-">"(" + * @param oper + * @return int + */ + public static int priority(String oper) { + int res = -1; + if (oper.equals(")")) { + res = 3; + } else if (oper.equals("*") || oper.equals("/")) { + res = 2; + } else if (oper.equals("+") || oper.equals("-")) { + res = 1; + } else if (oper.equals("(")) { + res = 0; + } else { + res = -1; + } + return res; + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ArrBinaryTreeDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ArrBinaryTreeDemo.java new file mode 100644 index 00000000..59ca8711 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ArrBinaryTreeDemo.java @@ -0,0 +1,80 @@ +package cn.lastwhisper.atguigu.tree; + +import cn.lastwhisper.util.ArrayUtil; + +/** + * @author cn.lastwhisper + */ +public class ArrBinaryTreeDemo { + public static void main(String[] args) { + + int[] arr = ArrayUtil.generateArrByOrder(7); + 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); + } +} + +/** + * 顺序存储二叉树基本思想: + * 将二叉树顺序存储到数组中,并能按照二叉树的规则遍历(先序、中序、后序) + */ +class ArrBinaryTree { + private int[] arr; + + public ArrBinaryTree(int[] arr) { + this.arr = arr; + } + + // 先序遍历 + public void preOrder(int index) { + if (arr == null || arr.length == 0) { + System.out.println("数组为空"); + return; + } + System.out.print(arr[index] + " "); + if ((2 * index + 1) < arr.length) { + preOrder(2 * index + 1); + } + if ((2 * index + 2) < arr.length) { + preOrder(2 * index + 2); + } + } + + // 中序遍历 + public void infixOrder(int index) { + if (arr == null || arr.length == 0) { + System.out.println("数组为空"); + return; + } + if ((2 * index + 1) < arr.length) { + infixOrder(2 * index + 1); + } + System.out.print(arr[index] + " "); + if ((2 * index + 2) < arr.length) { + infixOrder(2 * index + 2); + } + } + + // 后序遍历 + public void postOrder(int index) { + if (arr == null || arr.length == 0) { + System.out.println("数组为空"); + return; + } + if ((2 * index + 1) < arr.length) { + postOrder(2 * index + 1); + } + if ((2 * index + 2) < arr.length) { + postOrder(2 * index + 2); + } + System.out.print(arr[index] + " "); + } + +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/BinaryTreeDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/BinaryTreeDemo.java new file mode 100644 index 00000000..50ff9a40 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/BinaryTreeDemo.java @@ -0,0 +1,396 @@ +package cn.lastwhisper.atguigu.tree; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; + +/** + * 二叉树的遍历:先序、中序、后序 + * 二叉树的查找:查找指定节点 + * + * @author cn.lastwhisper + */ +public class BinaryTreeDemo { + // 创建节点 + static HeroNode root = new HeroNode(1, "宋江"); + static HeroNode heroNode2 = new HeroNode(2, "吴用"); + static HeroNode heroNode3 = new HeroNode(3, "卢俊义"); + static HeroNode heroNode4 = new HeroNode(4, "林冲"); + static HeroNode heroNode5 = new HeroNode(5, "关胜"); + static HeroNode heroNode6 = new HeroNode(6, "花荣"); + // 手动创建二叉树 + static BinaryTree binaryTree = new BinaryTree(); + + static { + root.setLeft(heroNode2); + root.setRight(heroNode3); + heroNode3.setRight(heroNode4); + heroNode3.setLeft(heroNode5); + heroNode4.setRight(heroNode6); + binaryTree.setRoot(root); + } + + public static void main(String[] args) { + + // 先序遍历 + System.out.println("===============先序遍历================"); + binaryTree.preOrder(root); // 1,2,3,5,4 + // 中序遍历 + System.out.println("===============中序遍历================"); + binaryTree.infixOrder(root); // 2,1,5,3,4 + // 后序遍历 + System.out.println("===============后序遍历================"); + binaryTree.postOrder(root); // 2,5,4,3,1 + // 先序遍历查找 + System.out.println("===============先序遍历查找================"); + System.out.println(binaryTree.preOrderSearch(5)); + System.out.println("===============中序遍历查找================"); + System.out.println(binaryTree.infixOrderSearch(5)); + System.out.println("===============后序遍历查找================"); + System.out.println(binaryTree.postOrderSearch(5)); + //System.out.println("===============清空子树下的no=3节点================"); + //binaryTree.clear(3); + //binaryTree.preOrder(root); + System.out.println("===============二叉树的最大高度================"); + System.out.println(binaryTree.height()); + System.out.println("===============二叉树的节点数================"); + System.out.println(binaryTree.size()); + } + + // 测试二叉树的层级遍历 + @Test + public void testLayerTransverse() { + ArrayList> arrayLists = binaryTree.layerTransverse(); + for (ArrayList arrayList : arrayLists) { + for (String s : arrayList) { + System.out.print(s + "\t"); + } + System.out.println(); + } + } +} + +// 二叉树 +class BinaryTree { + private HeroNode root; + + + public HeroNode getRoot() { + return root; + } + + public void setRoot(HeroNode root) { + this.root = root; + } + + // 清空子树下的所有节点 + public void clear(int no) { + if (root != null) { + if (root.getNo() == no) { + root = null; + } else { + root.clear(no); + } + } else { + System.out.println("空树无法删除"); + } + + } + + //判断二叉树是否为空 + public boolean isEmpty() { + return root == null; + } + + /** + * 获取二叉树的高度 + * + * @param + * @return int + */ + public int height() { + return height(root); + } + + /** + * 递归遍历直到叶子节点 + * + * @param node + * @return int + */ + public int height(HeroNode node) { + if (node == null) { + return 0; + } else { + //递归获取左子树高度 + int l = height(node.getLeft()); + //递归获取右子树高度 + int r = height(node.getRight()); + //高度应该算更高的一边,(+1是因为要算上自身这一层) + return l > r ? l + 1 : r + 1; + } + } + + /** + * 获取二叉树的节点数 + * + * @param + * @return int + */ + public int size() { + return size(root); + } + + public int size(HeroNode node) { + if (node == null) { + return 0; + } else { + return 1 + size(node.getLeft()) + size(node.getRight()); + } + + } + // 返回某节点的父节点 + + + // 先序遍历查找 + public HeroNode preOrderSearch(int no) { + if (root != null) { + return root.preOrderSearch(no); + } else { + return null; + } + } + + // 中序遍历查找 + public HeroNode infixOrderSearch(int no) { + if (root != null) { + return root.infixOrderSearch(no); + } else { + return null; + } + } + + // 后序遍历查找 + public HeroNode postOrderSearch(int no) { + if (root != null) { + return root.postOrderSearch(no); + } else { + return null; + } + } + + /** + * 先序遍历(递归) + * 先访问根节点,再先序遍历左子树,再先序遍历右子树 + * + * @param node + */ + public void preOrder(HeroNode node) { + if (node != null) { + System.out.println(node); + preOrder(node.getLeft()); + preOrder(node.getRight()); + } + } + + /** + * 中序遍历(递归) + * 先遍历左子树,再访问根节点,再中序遍历右子树 + * + * @param node + */ + public void infixOrder(HeroNode node) { + if (node != null) { + infixOrder(node.getLeft()); + System.out.println(node); + infixOrder(node.getRight()); + } + } + + /** + * 后序遍历(递归) + * 先遍历左子树,再后序遍历右子树,再访问根节点 + * + * @param node + */ + public void postOrder(HeroNode node) { + if (node != null) { + postOrder(node.getLeft()); + postOrder(node.getRight()); + System.out.println(node); + } + } + + public ArrayList> layerTransverse() { + ArrayList> tree = new ArrayList>(); + if (this.root == null) return tree; + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + ArrayList list = new ArrayList(); + int size = queue.size(); + for (int i = 0; i < size; i++) { + HeroNode node = queue.poll(); + list.add(node.getName()); + if (node.getLeft() != null) queue.add(node.getLeft()); + if (node.getRight() != null) queue.add(node.getRight()); + } + tree.add(list); + } + return tree; + } + +} + +// 树的节点 +class HeroNode { + private int no; + private String name; + private HeroNode left; + private HeroNode right; + + public HeroNode(int no, String name) { + this.no = no; + this.name = name; + } + + public int getNo() { + return no; + } + + public void setNo(int no) { + this.no = no; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public HeroNode getLeft() { + return left; + } + + public void setLeft(HeroNode left) { + this.left = left; + } + + public HeroNode getRight() { + return right; + } + + public void setRight(HeroNode right) { + this.right = right; + } + + @Override + public String toString() { + return "HeroNode{" + + "no=" + no + + ", name='" + name + '\'' + + '}'; + } + + /** + * 先序遍历查找节点 + * + * @param no + * @return cn.cn.lastwhisper.tree.HeroNode + */ + public HeroNode preOrderSearch(int no) { + // 1)、判断当前节点是否为查找的节点 + if (this.no == no) { + return this; + } + // 返回值 + HeroNode result = null; + // 2)、递归左子树 + if (this.left != null) { + result = this.left.preOrderSearch(no); + } + if (result != null) { + return result; + } + // 3)、递归右子树 + if (this.right != null) { + result = this.right.preOrderSearch(no); + } + return result; + } + + /** + * 中序遍历查找 + * + * @param no + * @return cn.cn.lastwhisper.tree.HeroNode + */ + public HeroNode infixOrderSearch(int no) { + HeroNode result = null; + // 1)、先递归左子树 + if (this.left != null) { + result = this.left.infixOrderSearch(no); + } + if (result != null) { + return result; + } + // 2)、判断当前节点是否为查找的节点 + if (this.no == no) { + return this; + } + // 3)、递归右子树 + if (this.right != null) { + result = this.right.infixOrderSearch(no); + } + return result; + } + + // 后序遍历查找 + public HeroNode postOrderSearch(int no) { + // 1)、递归遍历右子树 + HeroNode result = null; + if (this.right != null) { + result = this.right.postOrderSearch(no); + } + if (result != null) { + return result; + } + // 2)、判断该节点是否是寻找的节点 + if (this.no == no) { + return this; + } + // 3、递归遍历左子树 + if (this.left != null) { + result = this.left.postOrderSearch(no); + } + return result; + } + + // 递归删除节点 + public void clear(int no) { + // 1)、判断当前节点的左节点是否满足条件 + if (this.left != null && this.left.no == no) { + this.left = null; + return; + } + // 2)、判断当前节点的右节点是否满足条件 + if (this.right != null && this.right.no == no) { + this.right = null; + return; + } + // 3)、当前节点的左右节点不满足条件,递归左节点 + if (this.left != null) { + this.left.clear(no); + } + // 4)、当前节点的左右节点不满足条件,递归右节点 + if (this.right != null) { + this.right.clear(no); + } + } + + +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ThreadingBinaryTreeDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ThreadingBinaryTreeDemo.java new file mode 100644 index 00000000..b087fc40 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ThreadingBinaryTreeDemo.java @@ -0,0 +1,254 @@ +package cn.lastwhisper.atguigu.tree; + +/** + * 线索化二叉树 + * @author cn.lastwhisper + */ +public class ThreadingBinaryTreeDemo { + public static void main(String[] args) { + // 创建节点 + ThreadingHeroNode root = new ThreadingHeroNode(1, "宋江"); + ThreadingHeroNode heroNode2 = new ThreadingHeroNode(3, "吴用"); + ThreadingHeroNode heroNode3 = new ThreadingHeroNode(6, "卢俊义"); + ThreadingHeroNode heroNode4 = new ThreadingHeroNode(8, "林冲"); + ThreadingHeroNode heroNode5 = new ThreadingHeroNode(10, "关胜"); + ThreadingHeroNode heroNode6 = new ThreadingHeroNode(14, "花荣"); + + // 手动创建线索二叉树 + ThreadingBinaryTree ThreadingBinaryTree = new ThreadingBinaryTree(); + root.setLeft(heroNode2); + root.setRight(heroNode3); + heroNode2.setLeft(heroNode4); + heroNode2.setRight(heroNode5); + heroNode3.setLeft(heroNode6); + ThreadingBinaryTree.setRoot(root); + System.out.println("===============先序线索化二叉树================"); + ThreadingBinaryTree.preOrderThreading(); + //System.out.println("===============中序线索化二叉树================"); + //ThreadingBinaryTree.infixOrderThreading(); + System.out.println("===============前驱、后继节点================"); + ThreadingHeroNode heroNode5Left = heroNode5.getLeft();// 3 + ThreadingHeroNode heroNode5Right = heroNode5.getRight(); // + System.out.println("10号节点的前驱:" + heroNode5Left + "\n10号节点的后继:" + heroNode5Right); + System.out.println("===============先序遍历线索化二叉树================"); + ThreadingBinaryTree.preOrder(); + //System.out.println("===============中序遍历线索化二叉树================"); + //ThreadingBinaryTree.infixOrder(); + } +} + +// 线索化二叉树 +class ThreadingBinaryTree { + private ThreadingHeroNode root; + private ThreadingHeroNode preNode; + + + public ThreadingHeroNode getRoot() { + return root; + } + + public void setRoot(ThreadingHeroNode root) { + this.root = root; + } + + // 构建先序线索化二叉树 + public void preOrderThreading() { + this.preOrderThreading(root); + } + + // 构建中序线索化二叉树 + public void infixOrderThreading() { + this.infixOrderThreading(root); + } + + /** + * 先序遍历先序线索化二叉树 + * + */ + 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(); + } + } + + /** + * 中序遍历中序线索化二叉树 + * + */ + public void infixOrder() { + ThreadingHeroNode node = root; + while (node != null) { + // 找到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(); + } + } + + /** + * 构建先序线索化二叉树 + * + * @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) { + // 线索化左子树 + preOrderThreading(node.getLeft()); + } + if (node.getRightType() == 0) { + // 线索化右子树 + preOrderThreading(node.getRight()); + } + + } + + /** + * 构建中序线索化二叉树 + * + * @param node 当前需要线索化的节点 + */ + public void infixOrderThreading(ThreadingHeroNode node) { + // 数据校验 + if (node == null) { + return; + } + + // 1)、先线索化左子树 + infixOrderThreading(node.getLeft()); + // 2)、处理当前节点的前驱节点 + // 如果当前节点的左子树为空,说明出现了空指针域,需要构建线索前驱节点的线索 + if (node.getLeft() == null) { + // 设置当前节点的前驱节点 + node.setLeft(preNode); + node.setLeftType(1); + } + // 3)、处理前一个节点的后继节点 + // 如果前一个节点的左子树为空,说明出现了空指针域,需要构建线索后继节点的线索 + if (preNode != null && preNode.getRight() == null) { + // 设置前一个节点的后继节点为当前节点 + preNode.setRight(node); + preNode.setRightType(1); + } + // 每处理一个当前节点,就让当前节点是下一个节点的前驱节点 + preNode = node; + + // 4)、线索化右子树 + infixOrderThreading(node.getRight()); + } +} + +// 树的节点 +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指向后继节点 + + public ThreadingHeroNode(int no, String name) { + this.no = no; + this.name = name; + } + + public int getLeftType() { + return leftType; + } + + public void setLeftType(int leftType) { + this.leftType = leftType; + } + + public int getRightType() { + return rightType; + } + + public void setRightType(int rightType) { + this.rightType = rightType; + } + + public int getNo() { + return no; + } + + public void setNo(int no) { + this.no = no; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ThreadingHeroNode getLeft() { + return left; + } + + public void setLeft(ThreadingHeroNode left) { + this.left = left; + } + + public ThreadingHeroNode getRight() { + return right; + } + + public void setRight(ThreadingHeroNode right) { + this.right = right; + } + + @Override + public String toString() { + return "HeroNode{" + + "no=" + no + + ", name='" + name + '\'' + + '}'; + } + + +} 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/atguigu/tree/huffmancode/HuffmanCode.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmancode/HuffmanCode.java new file mode 100644 index 00000000..11ba50fc --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmancode/HuffmanCode.java @@ -0,0 +1,508 @@ +package cn.lastwhisper.atguigu.tree.huffmancode; + +import java.io.*; +import java.util.*; + +/** + * 哈夫曼编码 + * @author cn.lastwhisper + */ +public class HuffmanCode { + + // 构建哈夫曼编码表的值,左边为0,右边为1,即a:110的110 + static StringBuffer sb = new StringBuffer(); + // 哈夫曼编码表,key为字符,value为编码的值。如:a:110,key=a,value=110 + static Map huffmanCodes = new HashMap<>(); + + public static void main(String[] args) { + + /*--------------------------------压缩与解压的实际应用------------------------------------*/ + + //测试压缩文件 + String srcFile = "d://src.bmp"; + String dstFile = "d://src.bmp.zip"; + zipFile(srcFile, dstFile); + System.out.println("压缩文件ok~~"); + + + //测试解压文件 + //String zipFile = "d://src.bmp.zip"; + //String dstFile = "d://src2.bmp"; + //unZipFile(zipFile, dstFile); + //System.out.println("解压成功!"); + + /*--------------------------------压缩与解压的实现步骤------------------------------------*/ + + //// String在jdk11时byte value[],jdk11以下char value[] + //String content = "i like like like java do you like a java";//压缩前 40个char + //byte[] compressBytes = huffmanZip(content); //压缩后 17个byte + // 哈夫曼编码压缩后的字节数组:[-88, -65, -56, -65, -56, -65, -55, 77, -57, 6, -24, -14, -117, -4, -60, -90, 28] + //System.out.println("哈夫曼编码压缩后的字节数组:" + Arrays.toString(compressBytes)); + + //String bitString = byteToBitString(true, (byte) 1); + //System.out.println("夫曼编码压缩后的字节转比特:"+bitString); + + //byte[] unZipBytes = unzip(huffmanCodes, compressBytes); + // 哈夫曼编码解压缩后的字节数组:i like like like java do you like a java + //System.out.println("哈夫曼编码解压缩后的字节数组:" + new String(unZipBytes)); + + /*--------------------------------压缩的实现步骤------------------------------------*/ + + //System.out.println("==========测试:待压缩字符串——》二叉树节点========"); + //// Node{data=32, weight=9}, Node{data=97, weight=5}, Node{data=100, weight=1}, Node{data=101, weight=4}, Node{data=117, weight=1}, Node{data=118, weight=2}, + //// Node{data=105, weight=5}, Node{data=121, weight=1}, Node{data=106, weight=2}, Node{data=107, weight=4}, Node{data=108, weight=4}, Node{data=111, weight=2} + //List listNode = getListNode(content); + ////System.out.println(listNode); + //System.out.println("==========测试:二叉树节点——》哈夫曼树========"); + //Node root = createHuffmanTree(listNode); + //// 40,17,8,4,4... + ////preOrder(root); + //System.out.println("==========测试:哈夫曼树——》哈夫曼编码表========"); + //// a:100 k: 1110 + //Map huffmanCodes = getCodes(root); + //// 32=01, 97=100, 100=11000, 117=11001, 101=1110, 118=11011, 105=101, 121=11010, 106=0010, 107=1111, 108=000, 111=0011 + ////System.out.println("哈夫曼编码表:" + huffmanCodes); + //byte[] huffmanCodeBytes = zip(content, huffmanCodes); + //System.out.println("==========测试:哈夫曼编码表——》哈夫曼编码========"); + //// [-88, -65, -56, -65, -56, -65, -55, 77, -57, 6, -24, -14, -117, -4, -60, -90, 28] + //System.out.println("哈夫曼编码:" + Arrays.toString(huffmanCodeBytes)); + + } + + /** + * 对压缩文件的解压 + * @param zipFile 准备解压的文件 + * @param dstFile 将文件解压到哪个路径 + */ + public static void unZipFile(String zipFile, String dstFile) { + + //定义文件输入流 + InputStream is = null; + //定义一个对象输入流 + ObjectInputStream ois = null; + //定义文件的输出流 + OutputStream os = null; + try { + //创建文件输入流 + is = new FileInputStream(zipFile); + //创建一个和 is关联的对象输入流 + ois = new ObjectInputStream(is); + //读取byte数组 huffmanBytes + byte[] huffmanBytes = (byte[]) ois.readObject(); + //读取赫夫曼编码表 + Map huffmanCodes = (Map) ois.readObject(); + //解码 + byte[] bytes = unzip(huffmanCodes, huffmanBytes); + //将bytes 数组写入到目标文件 + os = new FileOutputStream(dstFile); + //写数据到 dstFile 文件 + os.write(bytes); + } catch (Exception e) { + System.out.println(e.getMessage()); + } finally { + + try { + if (os != null) os.close(); + if (ois != null) ois.close(); + if (is != null) is.close(); + } catch (Exception e2) { + System.out.println(e2.getMessage()); + } + + } + } + + //编写方法,将一个文件进行压缩 + + /** + * + * @param srcFile 你传入的希望压缩的文件的全路径 + * @param dstFile 我们压缩后将压缩文件放到哪个目录 + */ + public static void zipFile(String srcFile, String dstFile) { + + //创建输出流 + OutputStream os = null; + ObjectOutputStream oos = null; + //创建文件的输入流 + FileInputStream is = null; + try { + //创建文件的输入流 + is = new FileInputStream(srcFile); + //创建一个和源文件大小一样的byte[] + byte[] b = new byte[is.available()]; + //读取文件 + is.read(b); + //直接对源文件压缩 + byte[] huffmanBytes = huffmanZip(b); + //创建文件的输出流, 存放压缩文件 + os = new FileOutputStream(dstFile); + //创建一个和文件输出流关联的ObjectOutputStream + oos = new ObjectOutputStream(os); + //把 赫夫曼编码后的字节数组写入压缩文件 + oos.writeObject(huffmanBytes); //我们是把 + //这里我们以对象流的方式写入 赫夫曼编码,是为了以后我们恢复源文件时使用 + //注意一定要把赫夫曼编码 写入压缩文件 + oos.writeObject(huffmanCodes); + + } catch (Exception e) { + System.out.println(e.getMessage()); + } finally { + try { + if (is != null) is.close(); + if (oos != null) oos.close(); + if (os != null) os.close(); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + + } + + /** + * + * + * @param huffmanCodes 哈夫曼编码表 + * @param huffmanZipBytes 哈夫曼编码压缩后的字节数组 + * @return byte[] + */ + public static byte[] unzip(Map huffmanCodes, byte[] huffmanZipBytes) { + // 1)、将哈夫曼编码压缩后的字节数组还原为哈夫曼编码 + StringBuilder sbHuffmanCodeBytes = new StringBuilder(); + for (int i = 0; i < huffmanZipBytes.length; i++) { + // 是否补位、截取;除了最后一个字节都为false + boolean flag = (huffmanZipBytes.length - 1) == i; + sbHuffmanCodeBytes.append(byteToBitString(!flag, huffmanZipBytes[i])); + } + // 霍夫曼编码压缩后的字节数组对应的霍夫曼编码:1010100010111111110010001011111111001000101111111100100101001101110001110000011011101000111100101000101111111100110001001010011011100 + //System.out.println("被压缩的哈夫曼编码=" + sbHuffmanCodeBytes.toString()); + // 2)、将哈夫曼编码表进行反转调换,调转后:100:97 + Map reverseMap = new HashMap<>(); + for (Map.Entry entry : huffmanCodes.entrySet()) { + reverseMap.put(entry.getValue(), entry.getKey()); + } + // 原map:{32=01, 97=100, 100=11000, 117=11001, 101=1110, 118=11011, 105=101, 121=11010, 106=0010, 107=1111, 108=000, 111=0011} + // 反转map:{000=108, 01=32, 100=97, 101=105, 11010=121, 0011=111, 1111=107, 11001=117, 1110=101, 11000=100, 11011=118, 0010=106} + //System.out.println(reverseMap); + // 3)、遍历哈夫曼编码sbHuffmanCodeBytes,遍历到的每一个字符串作为key; + // 将key放到反转哈夫曼编码表中查询取出对应有效的value,添加到还原的字节组数中, + // 同时下次遍历哈夫曼编码sbHuffmanCodeBytes时从上次遍历到的主串之后开始遍历。 + // 示例:如子串key=000,在主串10101000中匹配到了000,说明key对应的value=108,ascii 108对应字符'L',将108添加到还原的字节数组中, + // 同时下次遍历哈夫曼编码sbHuffmanCodeBytes时下标从10101000之后开始遍历。 + // 还原的字节数组,这里使用list代替 + List list = new ArrayList<>(); + for (int i = 0; i < sbHuffmanCodeBytes.length(); ) { + // i与index配合遍历一个字符串 + int index = 1; + // 找到原字节 + boolean flag = true; + // 原字节 + Byte b = null; + // (i + index) <= sbHuffmanCodeBytes.length()防止截取字符串时越界 + while (flag && (i + index) <= sbHuffmanCodeBytes.length()) { + // 第一次for循环i=0,截取字符串[0,1],[0,2]...[0,length-1] + // 第二次for循环i=1,截取字符串[1,2],[1,3]...[1,length-1] + // 寻找编码对应的原字节 + String key = sbHuffmanCodeBytes.substring(i, i + index); + b = reverseMap.get(key); + if (b == null) { + index++; + } else { + flag = false; + } + } + list.add(b); + // 在(i, i + index)匹配到编码后,不用i++匹配(i+1,i+index)的主串, + // 因为哈夫曼编码是最优前缀编码,所以在(i+1,i+index)的编码不会有重复,直接匹配(i+index,length-1)的主串即可。 + i += index; + } + //当for循环结束后,我们list中就存放了所有的字符 "i like like like java do you like a java" + //把list 中的数据放入到byte[] 并返回 + byte[] b = new byte[list.size()]; + for (int i = 0; i < b.length; i++) { + b[i] = list.get(i); + } + return b; + } + + /** + * [-88, -65, -56, -65, -56, -65, -55, 77, -57, 6, -24, -14, -117, -4, -60, -90, 28] + * 将byte转为bit + * 情况一:负数,-1 + * Integer.toBinaryString(-1)返回的二进制补码:11111111111111111111111111111111 + * 负数的补码,太长需要截取 + * 正确:1111 1111 + * 情况二:正数:1 + * Integer.toBinaryString(-1)返回的二进制补码:1 + * 正数的补码就是自己,补码太短,需要补高位之后再截取 + * 正确:0000 0001 + * 情况三:最后一个字节不需要补位,28 + * 因为前面将哈夫曼编码转为byte[]时(zip方法)最后不足八位的字符串直接当做一个字节数组了, + * 所以再将byte转为bit时,最后一个字节不需要补位!!! + * 正确:11100 + * + * @param flag 是否需要补位,true表示需要补位,false表示不需要补位 + * @param b 需要转换的byte + * @return java.lang.String byte转换后的bitString(补码) + */ + public static String byteToBitString(boolean flag, byte b) { + // 将byte转为int + int temp = b; + // 如果是正数需要补高位 + if (flag) { + temp |= 256; // 按位与:256的二进制1 0000 0000 | 1 = 1 0000 0001 + } + String bitString = Integer.toBinaryString(temp); // 返回的是二进制补码 + if (flag) { + // int负数的补码长度为64,截取[1,8],其中8为byte的长度 + // 正数补高位后长度为9,截取[1,8],其中8为byte的长度 + return bitString.substring(bitString.length() - 8); + } else { + return bitString; + } + } + + + /** + * 核心方法,以哈夫曼编码的方式压缩字节数组 + * + * @param content 原字符串 + * @return byte[] 压缩后的字节数组 + */ + public static byte[] huffmanZip(String content) { + byte[] bytes = content.getBytes(); + return huffmanZip(bytes); + } + + /** + * 核心方法,以哈夫曼编码的方式压缩字节数组 + * + * @param bytes 原字节数组 + * @return byte[] 压缩后的字节数组 + */ + public static byte[] huffmanZip(byte[] bytes) { + // 1)、将byte[]转为二叉树的节点 + List listNode = getListNode(bytes); + // 2)、将二叉树的节点的节点转为哈夫曼树 + Node huffmanTreeRoot = createHuffmanTree(listNode); + // 3)、根据哈夫曼树,找出哈夫曼编码表 + Map huffmanCodes = getCodes(huffmanTreeRoot); + // 4)、将哈夫曼编码表转为哈夫曼编码字符串 + // 再根据哈夫曼编码字符串,按每8位一个字节转为字节数组,该字节数组就是压缩后的数据。 + return zip(bytes, huffmanCodes); + } + + /** + * + * + * @param content 待压缩字符串 + * @param huffmanCodes 哈夫曼编码表 + * @return byte[] 压缩后的字节数组 + */ + public static byte[] zip(String content, Map huffmanCodes) { + byte[] bytes = content.getBytes(); + return zip(bytes, huffmanCodes); + } + + /** + * // 待压缩字符串——》 "i like like like java do you like a java" + * // 待压缩字节数组——》 'i',' ','l',...... + * 哈夫曼编码表——》 {32=01, 97=100, 100=11000, 117=11001, 101=1110, 118=11011, 105=101, 121=11010, 106=0010, 107=1111, 108=000, 111=0011} + * 哈夫曼编码字符串(二进制字符串)——》1010100010111111110010001011111111001000101111111100100101001101110001110000011011101000111100101000101111111100110001001010011011100 + * 哈夫曼编码byte[](8位一组对应一个byte)huffmanCodeBytes + * + * Integer.parseInt("10101000", 2)是按补码来看待这个字符串的 + * huffmanCodeBytes[0]=10101000(补码)——》10101000-1=10100111(反码)——》11011000(原码)=-88 + * + * @param bytes 待压缩字符串 + * @param huffmanCodes 哈夫曼编码表 + * @return byte[] 压缩后的字节数组 + */ + public static byte[] zip(byte[] bytes, Map huffmanCodes) { + // 数据校验 + if (bytes == null || huffmanCodes == null) { + return null; + } + // 1)、将哈夫曼编码表转为哈夫曼编码字符串 + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(huffmanCodes.get(b)); + } + // 2)、将哈夫曼编码字符串转为哈夫曼编码byte[] + // 先求出哈夫曼编码byte[]的长度 + int len; + if (sb.length() % 8 == 0) { + len = sb.length() / 8; + } else { + len = sb.length() / 8 + 1; + } + // 创建哈夫曼编码byte[] + byte[] huffmanCodeBytes = new byte[len]; + // huffmanCodeBytes的下标 + int index = 0; + for (int i = 0; i < sb.length(); i += 8) { + String huffmanCodeStr; + if (i + 8 > sb.length()) { + // 哈夫曼编码字符串剩余不足8位,直接当做一个字节 + huffmanCodeStr = sb.substring(i); + } else { + huffmanCodeStr = sb.substring(i, i + 8); + } + huffmanCodeBytes[index] = (byte) Integer.parseInt(huffmanCodeStr, 2); + index++; + } + return huffmanCodeBytes; + } + + /** + * 根据哈夫曼树建立哈弗曼编码表 + * + * @param root 根节点 + * @return java.array.Map + */ + public static Map getCodes(Node root) { + if (root == null) { + return null; + } + getCodes(root.left, "0", sb, huffmanCodes); + getCodes(root.right, "1", sb, huffmanCodes); + return huffmanCodes; + } + + /** + * 根据哈夫曼树建立哈弗曼编码表(递归) + * @param node 以node节点为root开始建立哈夫曼编码表 + * @param code 左边为0,右边为1 + * @param stringBuffer 拼接编码的值 + * @param huffmanCodes 存储哈夫曼编码表 + */ + public static void getCodes(Node node, String code, StringBuffer stringBuffer, Map huffmanCodes) { + // 拼接编码的值,如 a:1——a:11——a:110 + StringBuffer sb = new StringBuffer(stringBuffer); + sb.append(code); + // 非叶子节点,哈夫曼树只有叶子节点有data + if (node.data == null) { + // 向左递归 + getCodes(node.left, "0", sb, huffmanCodes); + // 向右递归 + getCodes(node.right, "1", sb, huffmanCodes); + } else { + // 叶子节点, + huffmanCodes.put(node.data, sb.toString()); + } + } + + // 先序遍历 + public static void preOrder(Node root) { + if (root != null) { + root.preOrder(); + } else { + System.out.println("空树!"); + } + } + + /** + * 创建哈夫曼树,并返回root节点 + * + * @param nodes 二叉树节点 + * @return Node 哈夫曼树根节点 + */ + public static Node createHuffmanTree(List nodes) { + + while (nodes.size() > 1) { + // 1)、将序列升序排序,每一个节点都可以看做是一颗最简单的二叉树 + Collections.sort(nodes); + // 2)、找到权值最小的二叉树(节点) + Node leftNode = nodes.get(0); + // 2)、找到权值次小的二叉树(节点) + Node rightNode = nodes.get(1); + // 3)、将两个权值最小的二叉树构成一颗新的二叉树,新二叉树的权值为前面两个二叉树权值之和。 + Node node = new Node(leftNode.weight + rightNode.weight); + node.left = leftNode; + node.right = rightNode; + // 4)、将新二叉树放入序列中,并移除两个权值最小的二叉树 + nodes.add(node); + nodes.remove(leftNode); + nodes.remove(rightNode); + } + return nodes.get(0); + } + + /** + * 将字符串转换成哈夫曼树节点 + * @param zipStr 待压缩字符串 + * @return java.array.List + */ + public static List getListNode(String zipStr) { + byte[] zipStrBytes = zipStr.getBytes(); + return getListNode(zipStrBytes); + } + + /** + * 将字符串转换成哈夫曼树节点 + * @param zipBytes 待压缩字节数组 + * @return java.array.List + */ + public static List getListNode(byte[] zipBytes) { + // 将字节数组按字节拆分,统计每个字节出现的次数(select count(byte) weight from zipBytes order by byte) + Map map = new HashMap<>(); + for (int i = 0; i < zipBytes.length; i++) { + Integer weight = map.get(zipBytes[i]); + if (weight == null) { + map.put(zipBytes[i], 1); + } else { + map.put(zipBytes[i], weight + 1); + } + } + List nodes = new ArrayList<>(); + // 把每一个键值对转成一个Node对象,并加入到nodes集合 + for (Map.Entry entry : map.entrySet()) { + nodes.add(new Node(entry.getKey(), entry.getValue())); + } + return nodes; + } + + +} + +// 哈夫曼树节点 +class Node implements Comparable { + Byte data; // 字节 + int weight; // 权值,主要用于构建哈夫曼树 + Node left; // 左子树 + Node right; // 右子树 + + public Node(int weight) { + this.weight = weight; + } + + public Node(Byte data, int weight) { + this.data = data; + this.weight = weight; + } + + // 先序遍历 + public void preOrder() { + System.out.println(this); + if (this.left != null) { + this.left.preOrder(); + } + if (this.right != null) { + this.right.preOrder(); + } + } + + @Override + public int compareTo(Node o) { + // 升序 + return this.weight - o.weight; + } + + @Override + public String toString() { + return "Node{" + + "data=" + data + + ", weight=" + weight + + '}'; + } +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmantree/HuffmanTree.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmantree/HuffmanTree.java new file mode 100644 index 00000000..4dd1b9a4 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmantree/HuffmanTree.java @@ -0,0 +1,97 @@ +package cn.lastwhisper.atguigu.tree.huffmantree; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * 哈夫曼树 + * @author cn.lastwhisper + */ +public class HuffmanTree { + public static void main(String[] args) { + int[] arr = {13, 7, 8, 3, 29, 6, 1}; + + Node root = createHuffmanTree(arr); + + preOrder(root);// 67,29,38,15,7,8,23,10,4,1,3,6,13 + } + + public static void preOrder(Node root) { + if (root != null) { + root.preOrder(); + } else { + System.out.println("空树!"); + } + } + + /** + * 创建哈夫曼树,并返回root节点 + * + * @param arr + * @return cn.cn.lastwhisper.tree.huffmantree.Node + */ + public static Node createHuffmanTree(int[] arr) { + + List nodes = new LinkedList<>(); + for (int i = 0; i < arr.length; i++) { + nodes.add(new Node(arr[i])); + } + + while (nodes.size() > 1) { + // 1)、将序列升序排序,每一个节点都可以看做是一颗最简单的二叉树 + Collections.sort(nodes); + // 2)、找到权值最小的二叉树(节点) + Node leftNode = nodes.get(0); + // 2)、找到权值次小的二叉树(节点) + Node rightNode = nodes.get(1); + // 3)、将两个权值最小的二叉树构成一颗新的二叉树,新二叉树的权值为前面两个二叉树权值之和。 + Node node = new Node(leftNode.value + rightNode.value); + node.left = leftNode; + node.right = rightNode; + + // 4)、将新二叉树放入序列中,并移除两个权值最小的二叉树 + nodes.add(node); + nodes.remove(leftNode); + nodes.remove(rightNode); + + } + return nodes.get(0); + } + +} + +// 哈夫曼树节点 +class Node implements Comparable { + int value;// 权值 + Node left;//左子树 + Node right;//右子树 + + public Node(int value) { + this.value = value; + } + + // 先序遍历 + public void preOrder() { + System.out.println(this); + if (this.left != null) { + this.left.preOrder(); + } + if (this.right != null) { + this.right.preOrder(); + } + } + + @Override + public String toString() { + return "Node{" + + "value=" + value + + '}'; + } + + @Override + public int compareTo(Node o) { + // 升序 + return this.value - o.value; + } +} 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/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 new file mode 100644 index 00000000..9d4710bc --- /dev/null +++ b/algorithms/interview/pom.xml @@ -0,0 +1,15 @@ + + + + algorithms + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + interview + + + \ No newline at end of file diff --git a/algorithms/interview/src/main/java/Main.java b/algorithms/interview/src/main/java/Main.java new file mode 100644 index 00000000..a89bcd4c --- /dev/null +++ b/algorithms/interview/src/main/java/Main.java @@ -0,0 +1,39 @@ +import java.util.Arrays; +import java.util.HashSet; +import java.util.Scanner; + +public class Main { + //public static void main(String[] args){ + // Scanner in = new Scanner(System.in); + // // 一个while就是一个测试用例 + // while(in.hasNext()){ + // int m = in.nextInt(); // 该测试用例后续接收的参数个数 + // int n = in.nextInt(); // 该测试用例后续接收的参数个数 + // long[] array = new long[m]; + // for(int i=0; i set = new HashSet<>(); + for (int i = 0; i < n; i++) { + String line =sc.nextLine(); + String[] arr = line.split(" "); + set.addAll(Arrays.asList(arr)); + } + System.out.println("sum:" + set.size()); + } + sc.close(); + } + +} \ 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/other/Main.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/other/Main.java new file mode 100644 index 00000000..c98fe0b8 --- /dev/null +++ b/algorithms/interview/src/main/java/cn/lastwhisper/interview/other/Main.java @@ -0,0 +1,50 @@ +package cn.lastwhisper.interview.other; + +import java.util.Scanner; + +/** + *给出一个长度为n的数组a,你需要在这个数组中找到一个长度至少为m的区间, + * 使得这个区间内的数字的和尽可能小。 + * @author lastwhisper + */ +public class Main { + + public int sum(int[] numbers, int m) { + if (numbers.length < m) + throw new IllegalArgumentException("Illegal argument numbers"); + int l = 0, r = numbers.length - 1, x = m; + int min = 0; + for (int i = l; i <= r; i++) { + min += numbers[i]; + } + for (int i = 0; i <= (r - m); i++) { + int temp = 0; + for (int j = i; j < x; j++) { + temp += numbers[j]; + } + if (temp < min) { + min = temp; + } + x++; + } + return min; + } + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + // 一个while就是一个测试用例 + while (scanner.hasNext()) { + int m = scanner.nextInt(); + int n = scanner.nextInt(); + int[] nums = new int[m]; + for (int i = 0; i < m; i++) { + nums[i] = scanner.nextInt(); + } + //int[] nums = {-2, 1, -1, -1, -1}; + //int n = 3; + System.out.println(new Main().sum(nums, n)); + } + + } + +} diff --git a/algorithms/interview/src/main/java/cn/lastwhisper/interview/scanner/Main.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/scanner/Main.java new file mode 100644 index 00000000..e8038c9a --- /dev/null +++ b/algorithms/interview/src/main/java/cn/lastwhisper/interview/scanner/Main.java @@ -0,0 +1,18 @@ +package cn.lastwhisper.interview.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/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 new file mode 100644 index 00000000..6689d525 --- /dev/null +++ b/algorithms/leetcode/array/pom.xml @@ -0,0 +1,25 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + cn.lastwhisper.leetcode + 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\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\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/\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 new file mode 100644 index 00000000..0d0a8aab --- /dev/null +++ b/algorithms/leetcode/binarytree/pom.xml @@ -0,0 +1,22 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + 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 new file mode 100644 index 00000000..6f55f76b --- /dev/null +++ b/algorithms/leetcode/dynamic/pom.xml @@ -0,0 +1,25 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + cn.lastwhisper.leetcode + 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/pom.xml b/algorithms/leetcode/greedy/pom.xml new file mode 100644 index 00000000..8db3234b --- /dev/null +++ b/algorithms/leetcode/greedy/pom.xml @@ -0,0 +1,16 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + cn.lastwhisper.leetcode + greedy + + + \ 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/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/pom.xml b/algorithms/leetcode/hashtable/pom.xml new file mode 100644 index 00000000..fcce6862 --- /dev/null +++ b/algorithms/leetcode/hashtable/pom.xml @@ -0,0 +1,16 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + cn.lastwhisper.leetcode + hashtable + + + \ 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_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\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\215\225\350\257\215\350\247\204\345\276\213_290_Easy/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\215\225\350\257\215\350\247\204\345\276\213_290_Easy/Solution1.java" new file mode 100644 index 00000000..951df703 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\215\225\350\257\215\350\247\204\345\276\213_290_Easy/Solution1.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.leetcode.hashtable.单词规律_290_Easy; + +import java.util.HashMap; +import java.util.Map; + +class Solution1 { + /** + * https://leetcode-cn.com/problems/word-pattern/ + * 核心思想:map + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public boolean wordPattern(String pattern, String str) { + if (pattern == null || str == null) return false; + String[] strArr = str.split(" "); + if (pattern.length() != strArr.length) return false; + Map map = new HashMap<>(); + for (int i = 0; i < strArr.length; i++) { + if (map.containsKey(pattern.charAt(i))) { + // key存在,value不相同false + // a=dog,a=cat false + if (!strArr[i].equals(map.get(pattern.charAt(i)))) return false; + } else { + // key不存在,value相同false + // a=dog,b=dog false + if (map.containsValue(strArr[i])) return false; + map.put(pattern.charAt(i), strArr[i]); + } + } + return true; + } + + public static void main(String[] args) { + System.out.println(new Solution1().wordPattern("abba", "dog cat cat dog")); + System.out.println(new Solution1().wordPattern("abba", "dog cat cat fish")); + System.out.println(new Solution1().wordPattern("aaaa", "dog cat cat dog")); + System.out.println(new Solution1().wordPattern("abba", "dog dog dog dog")); + System.out.println(new Solution1().wordPattern("", "dog")); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\220\214\346\236\204\345\255\227\347\254\246\344\270\262_205_Esay/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\220\214\346\236\204\345\255\227\347\254\246\344\270\262_205_Esay/Solution1.java" new file mode 100644 index 00000000..5c0f8927 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\220\214\346\236\204\345\255\227\347\254\246\344\270\262_205_Esay/Solution1.java" @@ -0,0 +1,35 @@ +package cn.lastwhisper.leetcode.hashtable.同构字符串_205_Esay; + +import java.util.HashMap; +import java.util.Map; + +class Solution1 { + /** + * https://leetcode-cn.com/problems/isomorphic-strings/ + * 核心思想:map + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public boolean isIsomorphic(String s, String t) { + if (s == null || t == null || s.length() != t.length()) return false; + Map map = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + if (map.containsKey(s.charAt(i))) { + // key存在,value不相同false + if (map.get(s.charAt(i)) != t.charAt(i)) return false; + } else { + // key不存在,value相同false + if (map.containsValue(t.charAt(i))) return false; + map.put(s.charAt(i), t.charAt(i)); + } + } + return true; + } + + public static void main(String[] args) { + System.out.println(new Solution1().isIsomorphic("egg", "add")); + System.out.println(new Solution1().isIsomorphic("foo", "bar")); + System.out.println(new Solution1().isIsomorphic("paper", "title")); + System.out.println(new Solution1().isIsomorphic("ab", "bb")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\220\214\346\236\204\345\255\227\347\254\246\344\270\262_205_Esay/Solution2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\220\214\346\236\204\345\255\227\347\254\246\344\270\262_205_Esay/Solution2.java" new file mode 100644 index 00000000..18a14cdd --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\220\214\346\236\204\345\255\227\347\254\246\344\270\262_205_Esay/Solution2.java" @@ -0,0 +1,30 @@ +package cn.lastwhisper.leetcode.hashtable.同构字符串_205_Esay; + +class Solution2 { + /** + * https://leetcode-cn.com/problems/isomorphic-strings/ + * 核心思想:位图 + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public boolean isIsomorphic(String s, String t) { + if (s == null || t == null || s.length() != t.length()) return false; + char[] sc = s.toCharArray(); + char[] tc = t.toCharArray(); + int[] map = new int[256]; + for (int i = 0; i < s.length(); i++) { + if(map[sc[i]]!=map[tc[i]+128]){ + return false; + } + map[sc[i]]=map[tc[i]+128]=t.charAt(i); + } + return true; + } + + public static void main(String[] args) { + System.out.println(new Solution2().isIsomorphic("egg", "add")); + System.out.println(new Solution2().isIsomorphic("foo", "bar")); + System.out.println(new Solution2().isIsomorphic("paper", "title")); + System.out.println(new Solution2().isIsomorphic("ab", "bb")); + } +} \ 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/\345\277\253\344\271\220\346\225\260_202_Easy/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Solution1.java" new file mode 100644 index 00000000..4c69ba49 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Solution1.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.hashtable.快乐数_202_Easy; + +import java.util.HashSet; +import java.util.Set; + +class Solution1 { + /** + * https://leetcode-cn.com/problems/happy-number/submissions/ + * 核心思路:直接按题意来 + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + public boolean isHappy(int n) { + Set set = new HashSet(); + while (true) { + int[] arr = split(n); + int sum = 0; + for (int i = 0; i < arr.length; i++) { + sum += arr[i] * arr[i]; + if (i == arr.length - 1) { + System.out.printf("%d^2 = ", arr[i]); + } else { + System.out.printf("%d^2 + ", arr[i]); + } + } + System.out.println(sum); + if (sum == 1) { + return true; + } else if (set.contains(sum)) { + return false; + } else { + set.add(sum); + } + n = sum; + } + } + + public int[] split(int num) { + int bit, ten, hundred; + if (num < 10) { + return new int[]{num}; + } else if (num < 100) { + bit = num % 10; + ten = num / 10; + return new int[]{bit, ten}; + } else { + bit = num % 10; + ten = num / 10 % 10; + hundred = num / 100; + return new int[]{bit, ten, hundred}; + } + } + public static void main(String[] args) { + System.out.println(new Solution1().isHappy(18)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Solution2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Solution2.java" new file mode 100644 index 00000000..b0d42fd3 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Solution2.java" @@ -0,0 +1,44 @@ +package cn.lastwhisper.leetcode.hashtable.快乐数_202_Easy; + + +import java.util.HashSet; +import java.util.Set; + +class Solution2 { + + /** + * https://leetcode-cn.com/problems/happy-number/submissions/ + * 核心思路:hash + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + public boolean isHappy(int n) { + Set set = new HashSet(); + while (true) { + int sum = 0, bit = 0; + while (n > 0) { + bit = n % 10; + sum += bit * bit; + if (n / 10 > 0) { + System.out.printf("%s^2 + ", bit); + } else { + System.out.printf("%s^2 = ", bit); + } + n /= 10; + } + System.out.println(sum); + if (sum == 1) { + return true; + } else if (set.contains(sum)) { + return false; + } else { + set.add(sum); + } + n = sum; + } + } + + public static void main(String[] args) { + System.out.println(new Solution2().isHappy(1812)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Solution3.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Solution3.java" new file mode 100644 index 00000000..81c4b49e --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Solution3.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.hashtable.快乐数_202_Easy; + +class Solution3 { + /** + * https://leetcode-cn.com/problems/happy-number/ + * 核心思路:快慢指针 + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public boolean isHappy(int n) { + int slow = n, fast = bitSquareSum(n); + while (slow != fast) { + slow = bitSquareSum(slow); + fast = bitSquareSum(fast); + fast = bitSquareSum(fast); + } + return slow == 1; + } + + public int bitSquareSum(int num) { + int sum = 0; + while (num > 0) { + int bit = num % 10; + sum += bit * bit; + num = num / 10; + } + return sum; + } + + public static void main(String[] args) { + System.out.println(new Solution3().isHappy(18)); + //System.out.println(new Solution3().bitSquareSum(4328)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Test.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Test.java" new file mode 100644 index 00000000..d07ef10f --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Test.java" @@ -0,0 +1,42 @@ +package cn.lastwhisper.leetcode.hashtable.快乐数_202_Easy; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author lastwhisper + */ +public class Test { + + public boolean isHappy(int n) throws InterruptedException { + System.out.println(n); + while (true) { + String[] arr = split(n); + int sum = 0; + for (int i = 0; i < arr.length; i++) { + sum += Integer.parseInt(arr[i]) * Integer.parseInt(arr[i]); + if (i == arr.length - 1) { + System.out.printf("%s^2 = ", arr[i]); + } else { + System.out.printf("%s^2 + ", arr[i]); + } + } + System.out.println(sum); + if (sum == 1) { + return true; + } + n = sum; + Thread.sleep(100); + } + } + + public String[] split(int num) { + String numStr = String.valueOf(num); + return numStr.split(""); + } + + public static void main(String[] args) throws InterruptedException { + System.out.println(new Test().isHappy(18)); + } +} + diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Test2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Test2.java" new file mode 100644 index 00000000..633c71e5 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/Test2.java" @@ -0,0 +1,30 @@ +package cn.lastwhisper.leetcode.hashtable.快乐数_202_Easy; + +class Test2 { + public boolean isHappy(int n) { + int slow = n, fast = bitSquareSum(n,"fast"); + while (slow != fast) { + slow = bitSquareSum(slow,"slow"); + fast = bitSquareSum(fast,"fast"); + fast = bitSquareSum(fast,"fast"); + } + return slow == 1; + } + + public int bitSquareSum(int num,String who) { + int sum = 0; + while (num > 0) { + int bit = num % 10; + sum += bit * bit; + System.out.printf("%d^2 + ", bit); + num = num / 10; + + } + System.out.println(sum+"\t"+who); + return sum; + } + + public static void main(String[] args) { + System.out.println(new Test2().isHappy(18)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/data" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/data" new file mode 100644 index 00000000..b6a41e8b --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\277\253\344\271\220\346\225\260_202_Easy/data" @@ -0,0 +1,40 @@ +18 +1^2 + 8^2 = 65 f +6^2 + 5^2 = 61 +6^2 + 1^2 = 37 f1 +3^2 + 7^2 = 58 +5^2 + 8^2 = 89 f2 +8^2 + 9^2 = 145 +1^2 + 4^2 + 5^2 = 42 f3 +4^2 + 2^2 = 20 +2^2 + 0^2 = 4 f4 +4^2 = 16 +1^2 + 6^2 = 37 f5 +3^2 + 7^2 = 58 +5^2 + 8^2 = 89 f6 +8^2 + 9^2 = 145 +1^2 + 4^2 + 5^2 = 42 f7 +4^2 + 2^2 = 20 +2^2 + 0^2 = 4 +4^2 = 16 + + +18 s +1^2 + 8^2 = 65 s1 +6^2 + 5^2 = 61 s2 +6^2 + 1^2 = 37 s3 +3^2 + 7^2 = 58 s4 +5^2 + 8^2 = 89 s5 +8^2 + 9^2 = 145 s6 +1^2 + 4^2 + 5^2 = 42 s7 +4^2 + 2^2 = 20 +2^2 + 0^2 = 4 +4^2 = 16 +1^2 + 6^2 = 37 +3^2 + 7^2 = 58 +5^2 + 8^2 = 89 +8^2 + 9^2 = 145 +1^2 + 4^2 + 5^2 = 42 +4^2 + 2^2 = 20 +2^2 + 0^2 = 4 +4^2 = 16 \ 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\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/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\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" new file mode 100644 index 00000000..d38c116e --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\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" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.hashtable.有效的字母异位词_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/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\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/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\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" new file mode 100644 index 00000000..688ca122 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\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" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.hashtable.有效的字母异位词_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/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" new file mode 100644 index 00000000..4753700c --- /dev/null +++ "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" @@ -0,0 +1,63 @@ +package cn.lastwhisper.leetcode.hashtable.根据字符出现频率排序_451_Middle; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class Solution1 { + /** + * https://leetcode-cn.com/problems/sort-characters-by-frequency/ + * 核心思想:桶排序,数组下标代表频率 + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * 执行用时 :32 ms, 在所有 Java 提交中击败了74.69%的用户 + * 内存消耗 :38.9 MB, 在所有 Java 提交中击败了95.29%的用户 + */ + public String frequencySort(String s) { + if (s == null || s.equals("")) return ""; + Map map = new HashMap<>(); + // 记录字符出现的最大频率 + int maxFreq = 0; + // 统计所有字符出现的频率 + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (map.containsKey(c)) { + map.put(c, map.get(c) + 1); + } else { + map.put(c, 1); + } + Integer freq = map.get(c); + maxFreq = freq > maxFreq ? freq : maxFreq; + } + // 按频率下标将字符存入对应桶中 + List[] buckets = new ArrayList[maxFreq + 1]; + for (Map.Entry entry : map.entrySet()) { + Integer freq = entry.getValue(); + if (buckets[freq] == null) { + buckets[freq] = new ArrayList<>(); + } + buckets[freq].add(entry.getKey()); + } + // 倒序组装字符串 + StringBuilder sb = new StringBuilder(); + for (int i = maxFreq ; i > 0; i--) { + List bucket = buckets[i]; + if (bucket != null) { + for (Character c : bucket) { + for (int j = 0; j < i; j++) { + sb.append(c); + } + } + } + } + return sb.toString(); + } + + + public static void main(String[] args) { + System.out.println(new Solution1().frequencySort("tree")); + System.out.println(new Solution1().frequencySort("cccaaa")); + System.out.println(new Solution1().frequencySort("Aabb")); + } +} \ 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/Solution2.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/Solution2.java" new file mode 100644 index 00000000..d2f21fcb --- /dev/null +++ "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/Solution2.java" @@ -0,0 +1,64 @@ +package cn.lastwhisper.leetcode.hashtable.根据字符出现频率排序_451_Middle; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class Solution2 { + /** + * https://leetcode-cn.com/problems/sort-characters-by-frequency/ + * 使用char数组代替StringBuilder + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * 执行用时 : 26 ms , 在所有 Java 提交中击败了 79.49% 的用户 + * 内存消耗 : 39.5 MB , 在所有 Java 提交中击败了 92.03% 的用户 + */ + public String frequencySort(String s) { + if (s == null || s.equals("")) return ""; + char[] sc = s.toCharArray(); + Map map = new HashMap<>(); + // 记录字符出现的最大频率 + int maxFreq = 0; + // 统计所有字符出现的频率 + for (int i = 0; i < sc.length; i++) { + char c = sc[i]; + if (map.containsKey(c)) { + map.put(c, map.get(c) + 1); + } else { + map.put(c, 1); + } + Integer freq = map.get(c); + maxFreq = freq > maxFreq ? freq : maxFreq; + } + // 按频率下标将字符存入对应桶中 + List[] buckets = new ArrayList[maxFreq + 1]; + for (Map.Entry entry : map.entrySet()) { + Integer freq = entry.getValue(); + if (buckets[freq] == null) { + buckets[freq] = new ArrayList(); + } + buckets[freq].add(entry.getKey()); + } + // 倒序组装字符串 + int index = 0; + for (int i = maxFreq; i > 0; i--) { + List bucket = buckets[i]; + if (bucket != null) { + for (Character c : bucket) { + for (int j = 0; j < i; j++) { + sc[index++] = c; + } + } + } + } + return new String(sc); + } + + + public static void main(String[] args) { + System.out.println(new Solution2().frequencySort("tree")); + System.out.println(new Solution2().frequencySort("cccaaa")); + System.out.println(new Solution2().frequencySort("Aabb")); + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..89eaf113 --- /dev/null +++ b/algorithms/leetcode/linkedlist/pom.xml @@ -0,0 +1,22 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + 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/pom.xml b/algorithms/leetcode/other/pom.xml new file mode 100644 index 00000000..072b2e0f --- /dev/null +++ b/algorithms/leetcode/other/pom.xml @@ -0,0 +1,16 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + cn.lastwhisper.leetcode + other + + + \ 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\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\266_146_\344\270\255\347\255\211/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" new file mode 100644 index 00000000..234e6866 --- /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/MyLRUCache.java" @@ -0,0 +1,144 @@ +package cn.lastwhisper.leetcode.other.LRU缓存机制_146_中等; + +import java.util.HashMap; +import java.util.Iterator; + +/** + * @author lastwhisper + */ +public class MyLRUCache { + + private HashMap cache; + private DoubleLinkedList lru; + private int capacity; + + public MyLRUCache(int capacity) { + this.cache = new HashMap<>(); + this.lru = new DoubleLinkedList(); + this.capacity = capacity; + } + + static class Node { + public int key, val; + public Node prev, next; + + public Node(int key, int val) { + this.key = key; + this.val = val; + } + } + + /** + * 1、添加节点到链表头 + * 2、删除某节点 + * 3、获取尾节点 + * 每一步操作都要维护相关节点prev、next指针的关系 + */ + static class DoubleLinkedList implements Iterable { + private Node head, tail; + private int size; + + public DoubleLinkedList() { + 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; + } + + } + + public void addFirst(Node node) { + node.next = head.next; + node.prev = head; + head.next.prev = node; + head.next = node; + size++; + } + + public void remove(Node node) { + node.prev.next = node.next; + node.next.prev = node.prev; + size--; + } + + public Node getLast() { + if (head == tail.prev) { + return null; + } + return tail.prev; + } + + public int size() { + return size; + } + + @Override + public Iterator iterator() { + return new Itr(); + } + } + + // 从cache中拿出val,将kv移动到lru首部 + public int get(int key) { + Node node = cache.get(key); + if (node != null) { + lru.remove(node); + lru.addFirst(node); + return node.val; + } + return -1; + } + + public void put(int key, int val) { + // 已经存在,更新cache中的值 + // 将已存在的kv移动到lru首部 + Node node = new Node(key, val); + if (cache.containsKey(key)) { + cache.put(key, node); + lru.remove(node); + lru.addFirst(node); + return; + } + // 不存在,容量超过限制,移除末尾元素 + if (lru.size() >= capacity) { + Node lastNode = lru.getLast(); + cache.remove(lastNode.key); + lru.remove(lastNode); + } + // 不存在,正常添加 + cache.put(key, node); + lru.addFirst(node); + } + + public static void main(String[] args) { + MyLRUCache lruCache = new MyLRUCache(3); + lruCache.put(1, 1); + lruCache.put(2, 2); + lruCache.put(3, 3);// 3-2-1 + int val = lruCache.get(2);// 2-3-1 + System.out.println("取出" + val); + lruCache.put(4, 4);// 4-2-3 + lruCache.put(5, 5);// 5-4-2 + DoubleLinkedList lru = lruCache.lru; + for (Node node : lru) { + System.out.println(node.key + "\t" + node.val); + } + } + +} + 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 new file mode 100644 index 00000000..92f2b873 --- /dev/null +++ b/algorithms/leetcode/pom.xml @@ -0,0 +1,35 @@ + + + + algorithms + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + leetcode + pom + + array + hashtable + linkedlist + stackqueue + binarytree + recursion-backtracking + dynamic + greedy + other + leetcode-common + binarysearch + union-find + week + bitoperation + dfsbfs + string + divide + + + + \ No newline at end of file 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/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 new file mode 100644 index 00000000..70e5a888 --- /dev/null +++ b/algorithms/leetcode/stackqueue/pom.xml @@ -0,0 +1,22 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + 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 new file mode 100644 index 00000000..ed39ef68 --- /dev/null +++ b/algorithms/offer/pom.xml @@ -0,0 +1,21 @@ + + + + algorithms + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + 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/\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/\345\215\225\344\276\213/Singleton6.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton6.java" new file mode 100644 index 00000000..ae6e0a63 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton6.java" @@ -0,0 +1,29 @@ +package cn.lastwhisper.offer.单例; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * 懒汉式之CAS + * @author cn.lastwhisper + */ +public class Singleton6 { + + private static final AtomicReference INSTANCE = new AtomicReference(); + + private Singleton6() { + + } + + public static Singleton6 getInstance() { + for (; ; ) { + Singleton6 singleton = INSTANCE.get(); + if (singleton != null) { + return singleton; + } + singleton = new Singleton6(); + if (INSTANCE.compareAndSet(null, singleton)) { + return singleton; + } + } + } +} 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/\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" "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" new file mode 100644 index 00000000..59f77334 --- /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/Solution_3_2.java" @@ -0,0 +1,86 @@ +package cn.lastwhisper.offer.面试题03_数组中重复的数字_简单; + +/** + * 数组中重复的数字 + * 题目二:不修改数组找出数组中重复的数字 + * @author cn.lastwhisper + */ +public class Solution_3_2 { + + public static void main(String[] args) { + // 1.长度为n的数组包含一个或多个重复数字 + int[] arr1 = {2, 3, 5, 4, 3, 2, 6, 7}; + // 2.数组中不包含重复数字 + int[] arr2 = {1, 2, 3, 4, 7, 7, 7}; + // 3.空指针 + int[] arr3 = null; + System.out.println(new Solution_3_2().getDuplicate(arr2)); + } + + /** + * 找到数组中一个重复的数字 + * 返回-1代表无重复数字或者输入无效 + */ + public int getDuplicate(int[] arr) { + //校验数据 + if (arr == null || arr.length == 0) { + System.out.println("数组未初始化"); + return -1; + } + for (int i = 0; i < arr.length; i++) { + //n+1个数,取值范围1~n + if (arr[i] < 1 || arr[i] > arr.length - 1) { + System.out.println("数组数字不符合要求:n+1个数,取值范围1~n"); + return -1; + } + } + // start从1起始,因为0时只有一个数无法重复; + int start = 1, end = arr.length - 1, middle; + while (end >= start) { + // (start-end)/2+end==(start+end)/2 + middle = ((end - start) >> 1) + start; + // 二分起始范围出现次数count + // 第一步:如:{2,3,5,4,3,2,6,7}在[1...4],start=1;end=7;middle=4;上出现的次数count=5(4个数出现5次,肯定重复,无法确定是那个数) + // 第二步:如:{2,3,5,4,3,2,6,7}在[1...2],start=1;end=4;middle=2;上出现的次数count=2(2个数出现2次,无重复;实际上重复了,但是目前无法检测) + // 第三步:如:{2,3,5,4,3,2,6,7}在[3...4],start=3;end=4;middle=3;上出现的次数count=2(2个数出现2次,无重复) + // 第四步:如:{2,3,5,4,3,2,6,7}在[3...3],start=3;end=3;middle=3;上出现的次数count=2(1个数出现2次,肯定重复,可以确定是哪个数) + int count = rangeCount(arr, start, middle); + // 结束了返回重复下标 + if (start == end) { + if (count > 1) { + return start; + } else { + break; + } + } + // 第一步:5>4-1+1成立,说明数组在该范围[1...4]内出现重复值,缩短end范围 + // 第二步:2>2-1+1不成立,说明数组在该范围[1...2]内没有出现重复值,缩短start范围 + // 第二步:2>3-3+1成立,说明数组在该范围[3...4]内出现重复值,缩短end范围 + if (count > (middle - start + 1)) { + end = middle; + } else { + //否则,在该范围没有重复值 + start = middle + 1; + } + } + return -1; + } + + /** + * 计算某数组所有元素在某范围出现的次数 + * 如:{2,3,5,4,3,2,6,7}在[1...3]上出现的次数count=4 + * @param arr 某数组 + * @param start 起始范围 + * @param end 结束范围 + * @return int + */ + private int rangeCount(int[] arr, int start, int end) { + int count = 0; + for (int i = 0; i < arr.length; i++) { + if (arr[i] >= start && arr[i] <= end) { + count++; + } + } + return count; + } +} \ 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\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 new file mode 100644 index 00000000..c67bc1b0 --- /dev/null +++ b/algorithms/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + cn.lastwhisper + algorithms + pom + 1.0-SNAPSHOT + + datastructure + offer + interview + algorithm + leetcode + algorithm-common + niuke + + + + + junit + junit + 4.12 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 8 + 8 + + + + + \ No newline at end of file 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/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/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/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/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/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/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/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/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/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/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/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/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/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/decorator/v2/Test.java b/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/Test.java deleted file mode 100644 index 9cd298e4..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/Test.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.desgin.pattern.structural.decorator.v2; - -public class Test { - public static void main(String[]args){ - ABattercake aBattercake; - aBattercake = new Battercake(); - aBattercake = new EggDecorator(aBattercake); - aBattercake = new EggDecorator(aBattercake); - aBattercake = new SausageDecorator(aBattercake); - System.out.println(aBattercake.getDesc()+"价格为:"+aBattercake.cost()); - } -} 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/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/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/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/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/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/distributed/gray/README.md b/distributed/gray/README.md new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/distributed/gray/README.md @@ -0,0 +1 @@ + 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/distributed/lock/jedis/src/main/java/cn/cunchang/asynqueue/RedisDelayingQueue.java b/distributed/lock/jedis/src/main/java/cn/cunchang/asynqueue/RedisDelayingQueue.java new file mode 100644 index 00000000..e9ca8024 --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/asynqueue/RedisDelayingQueue.java @@ -0,0 +1,97 @@ +package cn.cunchang.asynqueue; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import redis.clients.jedis.Jedis; + +import java.lang.reflect.Type; +import java.util.Set; +import java.util.UUID; + +/** + * 延时队列的实现 + * @author cunchang + */ +public class RedisDelayingQueue { + + private Type TaskType = new TypeReference>() { + + }.getType(); + + private Jedis jedis; + private String queueKey; + + public RedisDelayingQueue(Jedis jedis, String queueKey) { + this.jedis = jedis; + this.queueKey = queueKey; + } + + static class TaskItem { + public String id; + public T msg; + } + + public void delay(T msg) { + TaskItem task = new TaskItem(); + task.id = UUID.randomUUID().toString(); // 分配唯一的 uuid + task.msg = msg; + String s = JSON.toJSONString(task); // fastjson 序列化 + jedis.zadd(queueKey, System.currentTimeMillis() + 5000, s); // 塞入延时队列 ,5s 后再试 + } + + public void loop() { + while (!Thread.interrupted()) { + // 只取一条 + Set values = jedis.zrangeByScore(queueKey, 0, System.currentTimeMillis(), 0, 1); + if (values.isEmpty()) { + try { + Thread.sleep(500); // 歇会继续 + } catch (InterruptedException e) { + break; + } + continue; + } + String s = values.iterator().next(); + if (jedis.zrem(queueKey, s) > 0) { // 抢到了 + TaskItem task = JSON.parseObject(s, TaskType); // fastjson 反序列化 + this.handleMsg(task.msg); + } + } + } + + public void handleMsg(T msg) { + System.out.println(msg); + } + + public static void main(String[] args) { + Jedis jedis = new Jedis("192.168.108.129", 6379); + 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); + } + } + + }; + Thread consumer = new Thread() { + + @Override + public void run() { + queue.loop(); + } + + }; + producer.start(); + consumer.start(); + try { + producer.join(); + Thread.sleep(6000); + consumer.interrupt(); + consumer.join(); + } catch (InterruptedException e) { + } + } +} 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/distributed/lock/jedis/src/main/java/cn/cunchang/basic/StringOper.java b/distributed/lock/jedis/src/main/java/cn/cunchang/basic/StringOper.java new file mode 100644 index 00000000..3beefdbd --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/basic/StringOper.java @@ -0,0 +1,19 @@ +package cn.cunchang.basic; + +import redis.clients.jedis.Jedis; + +/** + * string数据结构的操作 + * @author cunchang + * @date 2019/11/24 + */ +public class StringOper { + + public static void main(String[] args) { + Jedis jedis = new Jedis("127.0.0.1", 6379); + // incr指令 + Long num = jedis.incr("num"); + System.out.println(num); + } + +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest.java new file mode 100644 index 00000000..442a9b29 --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest.java @@ -0,0 +1,47 @@ +package cn.cunchang.bloomfilter; + +import io.rebloom.client.Client; +import org.junit.Test; + +import java.util.List; + +/** + * 布隆过滤器测试 + * @author cunchang + */ +public class BloomTest { + + /** + * bloomfilter对于已经见过的元素不会误判 + */ + @Test + public void test1(){ + Client client = new Client("192.168.108.129", 6379); + for (int i = 0; i < 100000; i++) { + client.add("codehole", "user" + i); + boolean ret = client.exists("codehole", "user" +i); + if (!ret) { + System.out.println(i); + break; + } + } + } + + /** + * bloomfilter对于没见过的元素会误判 + */ + @Test + public void test2(){ + Client client = new Client("192.168.108.129", 6379); + for (int i = 0; i < 100000; i++) { + client.add("codehole", "user" + i); + boolean ret = client.exists("codehole", "user" + (i + 1)); + if (ret) { + System.out.println(i); + break; + } + } + + } + +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest2.java b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest2.java new file mode 100644 index 00000000..813dcae2 --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest2.java @@ -0,0 +1,62 @@ +package cn.cunchang.bloomfilter; + +import io.rebloom.client.Client; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +/** + * 测试bloomfilter的误判率 + * @author cunchang + */ +public class BloomTest2 { + + private String chars; + + { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 26; i++) { + builder.append((char) ('a' + i)); + } + chars = builder.toString(); + } + + private String randomString(int n) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < n; i++) { + int idx = ThreadLocalRandom.current().nextInt(chars.length()); + builder.append(chars.charAt(idx)); + } + return builder.toString(); + } + + private List randomUsers(int n) { + List users = new ArrayList<>(); + for (int i = 0; i < 100000; i++) { + users.add(randomString(64)); + } + return users; + } + + public static void main(String[] args) { + BloomTest2 bloomer = new BloomTest2(); + List users = bloomer.randomUsers(100000); + List usersTrain = users.subList(0, users.size() / 2); + List usersTest = users.subList(users.size() / 2, users.size()); + + Client client = new Client("192.168.108.129", 6379); + client.delete("codehold"); + for (String user : usersTrain) { + client.add("codehold",user); + } + int falses = 0; + for (String user : usersTest) { + boolean ret = client.exists("codehold", user); + if(ret){//true说明误判了 + falses++; + } + } + System.out.printf("%d %d\n",falses,usersTest.size()); + } +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest3.java b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest3.java new file mode 100644 index 00000000..3b3f78b3 --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest3.java @@ -0,0 +1,61 @@ +package cn.cunchang.bloomfilter; + +import io.rebloom.client.Client; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +/** + * @author cunchang + */ +public class BloomTest3 { + private String chars; + + { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 26; i++) { + builder.append((char) ('a' + i)); + } + chars = builder.toString(); + } + + private String randomString(int n) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < n; i++) { + int idx = ThreadLocalRandom.current().nextInt(chars.length()); + builder.append(chars.charAt(idx)); + } + return builder.toString(); + } + + private List randomUsers(int n) { + List users = new ArrayList<>(); + for (int i = 0; i < 100000; i++) { + users.add(randomString(64)); + } + return users; + } + + public static void main(String[] args) { + BloomTest3 bloomer = new BloomTest3(); + List users = bloomer.randomUsers(100000); + List usersTrain = users.subList(0, users.size() / 2); + List usersTest = users.subList(users.size() / 2, users.size()); + Client client = new Client("192.168.108.129", 6379); + client.delete("codehole"); + // 对应 bf.reserve 指令 + client.createFilter("codehole", 50000, 0.001); + for (String user : usersTrain) { + client.add("codehole", user); + } + int falses = 0; + for (String user : usersTest) { + boolean ret = client.exists("codehole", user); + if (ret) { + falses++; + } + } + System.out.printf("%d %d\n", falses, usersTest.size()); + } +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/GuavaBloom.java b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/GuavaBloom.java new file mode 100644 index 00000000..e663a39f --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/GuavaBloom.java @@ -0,0 +1,25 @@ +package cn.cunchang.bloomfilter; + +import com.google.common.hash.BloomFilter; +import com.google.common.hash.Funnel; +import com.google.common.hash.Funnels; + +/** + * @author cunchang + */ +public class GuavaBloom { + 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); + } + } + } +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/cluster/ClusterTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/cluster/ClusterTest.java new file mode 100644 index 00000000..0b12060d --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/cluster/ClusterTest.java @@ -0,0 +1,37 @@ +package cn.cunchang.cluster; + +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 集群测试 + * @author cunchang + */ +public class ClusterTest { + + public static void main(String[] args) { + Set nodeList = new HashSet<>(); + nodeList.add(new HostAndPort("192.168.108.131", 7000)); + nodeList.add(new HostAndPort("192.168.108.131", 7001)); + nodeList.add(new HostAndPort("192.168.108.131", 7002)); + nodeList.add(new HostAndPort("192.168.108.131", 7003)); + nodeList.add(new HostAndPort("192.168.108.131", 7004)); + nodeList.add(new HostAndPort("192.168.108.131", 7005)); + JedisPoolConfig poolConfig = new JedisPoolConfig(); + int timeout = 30_000; + JedisCluster jedisCluster = new JedisCluster(nodeList, timeout, poolConfig); + jedisCluster.set("hello", "world"); + System.out.println(jedisCluster.get("hello")); + + //获取所有节点的JedisPool + Map jedisPoolMap = jedisCluster.getClusterNodes(); + } + +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/cluster/JedisClusterFactory.java b/distributed/lock/jedis/src/main/java/cn/cunchang/cluster/JedisClusterFactory.java new file mode 100644 index 00000000..f85de56a --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/cluster/JedisClusterFactory.java @@ -0,0 +1,63 @@ +package cn.cunchang.cluster; + +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.JedisPoolConfig; + +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class JedisClusterFactory { + private JedisCluster jedisCluster; + private List hostPortList; + //超时时间 + private int timeout; + + public void init() { + //这里可以设置相关参数 + JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); + + //从配置文件中读取ip:port的参数放进Set中 + Set nodeSet = new HashSet<>(); + for (String hostPort : hostPortList) { + String[] arr = hostPort.split(":"); + if (arr.length != 2) { + continue; + } + nodeSet.add(new HostAndPort(arr[0], Integer.parseInt(arr[1]))); + } + + try { + jedisCluster = new JedisCluster(nodeSet, timeout, jedisPoolConfig); + } catch (Exception e) { + // logger + e.printStackTrace(); + } + } + + + public void destroy() { + if (jedisCluster != null) { + try { + jedisCluster.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public JedisCluster getJedisCluster() { + return jedisCluster; + } + + //spring注入hostPortList和timeout + public void setHostPortList(List hostPortList) { + this.hostPortList = hostPortList; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } +} \ No newline at end of file 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/distributed/lock/jedis/src/main/java/cn/cunchang/hyperloglog/PfTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/hyperloglog/PfTest.java new file mode 100644 index 00000000..ece304a0 --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/hyperloglog/PfTest.java @@ -0,0 +1,44 @@ +package cn.cunchang.hyperloglog; + +import cn.cunchang.common.Const; +import org.junit.Test; +import redis.clients.jedis.Jedis; + +/** + * @author cunchang + */ +public class PfTest { + + /** + * HyperLoglog的统计误差 + */ + @Test + public void test1() { + Jedis jedis = new Jedis(Const.IP, Const.PORT); + for (int i = 0; i < 1000; i++) { + jedis.pfadd("uv", "user" + i); + // 出现误差 + long total = jedis.pfcount("uv"); + if (total != i + 1) { + System.out.printf("%d %d\n", total, i + 1);//99 100 + break; + } + } + jedis.close(); + } + + /** + * HyperLoglog 一万次的误差情况 + */ + @Test + public void test2() { + Jedis jedis = new Jedis(Const.IP, Const.PORT); + for (int i = 0; i < 10000; i++) { + jedis.pfadd("uv", "user" + i); + } + long total = jedis.pfcount("uv"); + System.out.printf("%d %d\n", 10000, total);//10000 10064 + jedis.close(); + } + +} 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/distributed/lock/jedis/src/main/java/cn/cunchang/partition/PartitionTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/partition/PartitionTest.java new file mode 100644 index 00000000..e9e304f9 --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/partition/PartitionTest.java @@ -0,0 +1,93 @@ +package cn.cunchang.partition; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * hash分区 迁移率 + * @author cunchang + */ +public class PartitionTest { + private final static Object value = new Object(); + private static Integer data = 100; + private static Map node0 = new LinkedHashMap<>(); + private static Map node1 = new LinkedHashMap<>(); + private static Map node2 = new LinkedHashMap<>(); + + private static Map node3 = new LinkedHashMap<>(); + + + private static Map node4 = new LinkedHashMap<>(); + private static Map node5 = new LinkedHashMap<>(); + private static Map node6 = new LinkedHashMap<>(); + private static Map node7 = new LinkedHashMap<>(); + private static Map node8 = new LinkedHashMap<>(); + + private static List> oldNodes = new ArrayList<>(); + private static List> newNodes = new ArrayList<>(); + + static { + oldNodes.add(node0); + oldNodes.add(node1); + oldNodes.add(node2); + // 3节点扩容到4节点 + newNodes.add(node3); + newNodes.add(node4); + newNodes.add(node5); + newNodes.add(node6); + // 3节点扩容到6节点 + //newNodes.add(node7); + //newNodes.add(node8); + } + + public static void main(String[] args) { + // 将请求db的数据,缓存到cache中 + System.out.println("------------将请求db的数据缓存到3节点cache-----------"); + dbToCache(oldNodes); + System.out.println("----------扩容1个节点,变成4节点,需要数据迁移--------"); + dbToCache(newNodes); + + int count = 0;//数据发生迁移的量 + // 老节点对应新节点,数据发生迁移的量 + for (int i = 0; i < oldNodes.size(); i++) { + Map oldNode = oldNodes.get(i); + Map newNode = newNodes.get(i); + int oldSize = oldNode.size(); + oldNode.putAll(newNode); + int newSize = oldNode.size(); + count += newSize - oldSize; + } + // 新节点数据量 + for (int i = oldNodes.size(); i < newNodes.size(); i++) { + count += newNodes.get(i).size(); + } + System.out.println("数据迁移率:" + (count % 100)); //3节点——》4节点 迁移率74%;3节点——》6节点迁移率50% + + } + + public static void dbToCache(List> cache) { + for (int k = 1; k <= data; k++) { + int index = hash(k) % cache.size(); + cache.get(index).put(k, value); + } + print(cache); + } + + public static void print(List> cache) { + for (int i = 0; i < cache.size(); i++) { + Map node = cache.get(i); + System.out.println("结点" + i + " dbsize:" + node.size()); + System.out.print("结点" + i + " data:"); + for (Map.Entry entry : node.entrySet()) { + System.out.print(entry.getKey() + ","); + } + System.out.println(); + } + } + + public static int hash(Integer num) { + return num.hashCode(); + } +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/pipeline/PipelineTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/pipeline/PipelineTest.java new file mode 100644 index 00000000..33515f51 --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/pipeline/PipelineTest.java @@ -0,0 +1,43 @@ +package cn.cunchang.pipeline; + +import org.junit.Test; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.Pipeline; + +/** + * 流水线 + * @author cunchang + */ +public class PipelineTest { + //没有使用pipieline的情况下 + @Test + public void testWithoutPipeline() { + try (Jedis jedis = new Jedis("192.168.108.129", 6379)) { + long start = System.currentTimeMillis(); + for (int i = 1; i <= 10000; i++) { + jedis.hset("hashKey-" + i, "field-" + i, "value-" + i); + } + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start));//耗时:5393 + jedis.flushAll();//清空数据库,方便后续测试 + } + } + + //使用pipeline的情况下 + @Test + public void testPipeline() { + try (Jedis jedis = new Jedis("192.168.108.129", 6379)){ + long start = System.currentTimeMillis(); + for (int i = 0; i < 100; i++) { + Pipeline pipeline = jedis.pipelined(); + for (int j = i * 100; j < (i + 1) * 100; j++) { + pipeline.hset("hashKey-" + j, "field-" + j, "value-" + j); + } + pipeline.syncAndReturnAll(); + } + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start)); // 耗时:108 + jedis.flushAll();//清空数据库,方便后续测试 + } + } +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/PublisherTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/PublisherTest.java new file mode 100644 index 00000000..97812bfc --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/PublisherTest.java @@ -0,0 +1,16 @@ +package cn.cunchang.publishersubscriber; + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPubSub; + +/** + * @author cunchang + */ +public class PublisherTest { + //发布 + public static void main(String[] args){ + Jedis jedis = new Jedis("192.168.108.130" , 6379); + jedis.publish("aliTV" , "I am xuyinan"); + jedis.publish("googleTV" , "My age is 27"); + } +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/SubscriberTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/SubscriberTest.java new file mode 100644 index 00000000..41dc69ce --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/SubscriberTest.java @@ -0,0 +1,20 @@ +package cn.cunchang.publishersubscriber; + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPubSub; + +/** + * @author cunchang + */ +public class SubscriberTest { + //订阅 + public static void main(String[] args){ + Jedis jedis = new Jedis("192.168.108.130" , 6379); + jedis.subscribe(new JedisPubSub() { + @Override + public void onMessage(String channel, String message) { + System.out.println("receive channel ["+channel+"] message ["+message+"]"); + } + } , "aliTV" , "googleTV"); + } +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/sentinel/SentinelTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/sentinel/SentinelTest.java new file mode 100644 index 00000000..c0efbcb9 --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/sentinel/SentinelTest.java @@ -0,0 +1,62 @@ +package cn.cunchang.sentinel; + +import org.junit.Before; +import org.junit.Test; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPoolConfig; +import redis.clients.jedis.JedisSentinelPool; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * @author cunchang + */ +public class SentinelTest { + private JedisSentinelPool sentinelPool; + + // 准备数据 + @Before + public void before() { + Set sentinelSet = new HashSet() {{ + add("192.168.108.131:26379"); + add("192.168.108.131:26380"); + add("192.168.108.131:26381"); + }}; + JedisPoolConfig poolConfig = new JedisPoolConfig(); + String masterName = "mymaster"; + int timeout = 30_000; //jedis连接sentinel的超时时间 + sentinelPool = new JedisSentinelPool( + masterName, sentinelSet, poolConfig, timeout); + + } + /** + * 测试故障转移 + */ + @Test + public void failover() { + int count = 0; + while (true) { + count++; + Jedis jedis = sentinelPool.getResource(); + try { + int index = new Random().nextInt(10000); + String key = "k-" + index; + String value = "v-" + index; + jedis.set(key, value); + if(count%100==0){ + System.out.println("key:" + key + "\tvalue:" + jedis.get(key)); + } + TimeUnit.MILLISECONDS.sleep(10); + } catch (Exception e) { + System.out.println(e.getMessage()); + } finally { + if (jedis != null) jedis.close(); + } + } + } + + +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/transaction/TransactionTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/transaction/TransactionTest.java new file mode 100644 index 00000000..f3a5f6ed --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/transaction/TransactionTest.java @@ -0,0 +1,46 @@ +package cn.cunchang.transaction; + +import cn.cunchang.JedisUtil; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.Transaction; + +import java.util.List; + +/** + * redis事务测试 + * @author cunchang + */ +public class TransactionTest { + + public static void main(String[] args) { + Jedis jedis = JedisUtil.getJedis(); + String userId = "abc"; + String key = buildKey(userId); + jedis.setnx(key, String.valueOf(5)); // setnx 做初始化 + System.out.println(doubleAccount(jedis, userId)); + jedis.close(); + } + /** + * 乐观锁:watch + * + */ + public static int doubleAccount(Jedis jedis, String userId) { + String key = buildKey(userId); + while (true) { + jedis.watch(key); + int value = Integer.parseInt(jedis.get(key)); + value *= 2; // 加倍 + Transaction tx = jedis.multi(); + tx.set(key, String.valueOf(value)); + List res = tx.exec(); + if (res != null) { + break; // 成功了 + } + } + return Integer.parseInt(jedis.get(key)); // 重新获取余额 + } + + 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/distributed/mq/rabbitmq/rabbitmq-spring/src/main/resources/application.properties b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/resources/application.properties @@ -0,0 +1 @@ + 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/distributed/session/jwt-session/src/main/resources/application.properties b/distributed/session/jwt-session/src/main/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/distributed/session/jwt-session/src/main/resources/application.properties @@ -0,0 +1 @@ + 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/distributed/session/tomcat-session/src/main/resources/application.properties b/distributed/session/tomcat-session/src/main/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/distributed/session/tomcat-session/src/main/resources/application.properties @@ -0,0 +1 @@ + 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/distributed/springcloud-netflix/api-gateway/pom.xml b/distributed/springcloud-netflix/api-gateway/pom.xml new file mode 100644 index 00000000..cbd1d7ae --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/pom.xml @@ -0,0 +1,90 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + cn.lastwhisper + api-gateway + 0.0.1-SNAPSHOT + api-gateway + zuul网关 + + + 1.8 + Finchley.RELEASE + + + + + org.springframework.cloud + spring-cloud-starter-config + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + com.google.guava + guava + 28.0-jre + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + + diff --git a/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/ApiGatewayApplication.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/ApiGatewayApplication.java new file mode 100644 index 00000000..ee7a221a --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/ApiGatewayApplication.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.apigateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableZuulProxy +public class ApiGatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(ApiGatewayApplication.class, args); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..41b4ffdc --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/config/CorsConfig.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.apigateway.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import java.util.Arrays; +import java.util.Collections; + +/** + * 跨域配置 + * Created by 廖师兄 + * 2018-03-11 23:04 + * C - Cross O - Origin R - Resource S - Sharing + */ +@Configuration +public class CorsConfig { + + @Bean + public CorsFilter corsFilter() { + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + final CorsConfiguration config = new CorsConfiguration(); + + config.setAllowCredentials(true); + config.setAllowedOrigins(Collections.singletonList("*")); //http:www.a.com + config.setAllowedHeaders(Collections.singletonList("*")); + config.setAllowedMethods(Collections.singletonList("*")); + config.setMaxAge(300L); + + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d4084514 --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/config/ZuulConfig.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.apigateway.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.cloud.netflix.zuul.filters.ZuulProperties; +import org.springframework.stereotype.Component; + +/** + * 注册中心+zuul动态路由 + * @author lastwhisper + * @date 2019/11/1 + */ +@Component +public class ZuulConfig { + + @ConfigurationProperties("zuul") + @RefreshScope + public ZuulProperties zuulProperties(){ + return new ZuulProperties(); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..1035f3bd --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/constant/CookieConstant.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.apigateway.constant; + +/** + * Created by 廖师兄 + * 2018-03-04 23:28 + */ +public interface CookieConstant { + + String TOKEN = "token"; + + String OPENID = "openid"; + + /** + * 过期时间(单位:s) + */ + Integer expire = 7200; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..62a0ab3d --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/constant/RedisConstant.java @@ -0,0 +1,11 @@ +package cn.lastwhisper.apigateway.constant; + +/** + * Created by 廖师兄 + * 2018-03-04 23:37 + */ +public interface RedisConstant { + + String TOKEN_TEMPLATE = "token_%s"; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..5dddb8c0 --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/exception/RateLimitException.java @@ -0,0 +1,8 @@ +package cn.lastwhisper.apigateway.exception; + +/** + * Created by 廖师兄 + * 2018-03-11 23:56 + */ +public class RateLimitException extends RuntimeException { +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..37e9782f --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthBuyerFilter.java @@ -0,0 +1,63 @@ +package cn.lastwhisper.apigateway.filter; + +import cn.lastwhisper.apigateway.constant.CookieConstant; +import cn.lastwhisper.apigateway.utils.CookieUtil; +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; + + +/** + * @author lastwhisper + * @date 2019/11/1 + */ +@Component +public class AuthBuyerFilter extends ZuulFilter { + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Override + public String filterType() { + return FilterConstants.PRE_TYPE; + } + + @Override + public int filterOrder() { + return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; + } + + @Override + public boolean shouldFilter() { + RequestContext requestContext = RequestContext.getCurrentContext(); + HttpServletRequest request = requestContext.getRequest(); + if ("/order/order/create".equals(request.getRequestURI())) { + return true; + } + return false; + } + + @Override + public Object run() throws ZuulException { + RequestContext requestContext = RequestContext.getCurrentContext(); + HttpServletRequest request = requestContext.getRequest(); + /** + * /order/create buyer + */ + Cookie cookie = CookieUtil.get(request, CookieConstant.OPENID); + if (cookie == null || StringUtils.isEmpty(cookie.getValue())) { + requestContext.setSendZuulResponse(false); + requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); + } + return null; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..e1181a57 --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthFilter.java @@ -0,0 +1,74 @@ +package cn.lastwhisper.apigateway.filter; + +import cn.lastwhisper.apigateway.constant.CookieConstant; +import cn.lastwhisper.apigateway.constant.RedisConstant; +import cn.lastwhisper.apigateway.utils.CookieUtil; +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; + + +/** + * 区别买家与卖家 + * @author lastwhisper + * @date 2019/11/1 + */ +//@Component +public class AuthFilter extends ZuulFilter { + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Override + public String filterType() { + return FilterConstants.PRE_TYPE; + } + + @Override + public int filterOrder() { + return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() throws ZuulException { + RequestContext requestContext = RequestContext.getCurrentContext(); + HttpServletRequest request = requestContext.getRequest(); + /** + * /order/create buyer + * /order/finish seller + * /product/list buyer or seller + */ + if ("/order/order/create".equals(request.getRequestURI())) { + Cookie cookie = CookieUtil.get(request, CookieConstant.OPENID); + if (cookie == null || StringUtils.isEmpty(cookie.getValue())) { + requestContext.setSendZuulResponse(false); + requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); + } + } + + if ("/order/order/finish".equals(request.getRequestURI())) { + Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN); + if (cookie == null || StringUtils.isEmpty(cookie.getValue()) + || StringUtils.isEmpty(stringRedisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_TEMPLATE, cookie.getValue())))) { + requestContext.setSendZuulResponse(false); + requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); + } + } + + return null; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..c90cc0f5 --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthSellerFilter.java @@ -0,0 +1,66 @@ +package cn.lastwhisper.apigateway.filter; + +import cn.lastwhisper.apigateway.constant.CookieConstant; +import cn.lastwhisper.apigateway.constant.RedisConstant; +import cn.lastwhisper.apigateway.utils.CookieUtil; +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; + + +/** + * 区别买家与卖家 + * @author lastwhisper + * @date 2019/11/1 + */ +@Component +public class AuthSellerFilter extends ZuulFilter { + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Override + public String filterType() { + return FilterConstants.PRE_TYPE; + } + + @Override + public int filterOrder() { + return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; + } + + @Override + public boolean shouldFilter() { + RequestContext requestContext = RequestContext.getCurrentContext(); + HttpServletRequest request = requestContext.getRequest(); + if ("/order/order/finish".equals(request.getRequestURI())) { + return true; + } + return false; + } + + @Override + public Object run() throws ZuulException { + RequestContext requestContext = RequestContext.getCurrentContext(); + HttpServletRequest request = requestContext.getRequest(); + /** + * /order/finish seller + */ + Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN); + if (cookie == null || StringUtils.isEmpty(cookie.getValue()) + || StringUtils.isEmpty(stringRedisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_TEMPLATE, cookie.getValue())))) { + requestContext.setSendZuulResponse(false); + requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); + } + return null; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..3918330d --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/PostResponseHeaderFilter.java @@ -0,0 +1,42 @@ +package cn.lastwhisper.apigateway.filter; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * zuul 自定义后置处理器 + * @author lastwhisper + * @date 2019/11/1 + */ +@Component +public class PostResponseHeaderFilter extends ZuulFilter { + @Override + public String filterType() { + return FilterConstants.POST_TYPE; + } + + @Override + public int filterOrder() { + return FilterConstants.SEND_RESPONSE_FILTER_ORDER; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() throws ZuulException { + RequestContext requestContext = RequestContext.getCurrentContext(); + HttpServletResponse response = requestContext.getResponse(); + + response.setHeader("X-Foo", UUID.randomUUID().toString()); + return null; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..311be24f --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/PreTokenFilter.java @@ -0,0 +1,48 @@ +package cn.lastwhisper.apigateway.filter; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import org.apache.commons.lang.StringUtils; +import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; + + +/** + * zuul 自定义前置处理器 + * @author lastwhisper + * @date 2019/11/1 + */ +//@Component +public class PreTokenFilter extends ZuulFilter { + @Override + public String filterType() { + return FilterConstants.PRE_TYPE; + } + + @Override + public int filterOrder() { + return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() throws ZuulException { + RequestContext requestContext = RequestContext.getCurrentContext(); + HttpServletRequest request = requestContext.getRequest(); + //这里从url参数里获取, 也可以从cookie, header里获取 + String token = request.getParameter("token"); + if (StringUtils.isEmpty(token)) { + requestContext.setSendZuulResponse(false); + requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); + } + return null; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..cdfed43b --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/RateLimiterFilter.java @@ -0,0 +1,42 @@ +package cn.lastwhisper.apigateway.filter; + +import cn.lastwhisper.apigateway.exception.RateLimitException; +import com.google.common.util.concurrent.RateLimiter; +import com.netflix.zuul.ZuulFilter; +import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; +import org.springframework.stereotype.Component; + +/** + * 网关限流过滤器 + * @author lastwhisper + * @date 2019/11/1 + */ +//@Component +public class RateLimiterFilter extends ZuulFilter { + + private static final RateLimiter RATE_LIMITER = RateLimiter.create(100); + + @Override + public String filterType() { + return FilterConstants.PRE_TYPE; + } + + @Override + public int filterOrder() { + return FilterConstants.SERVLET_DETECTION_FILTER_ORDER - 1; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() { + if (!RATE_LIMITER.tryAcquire()) { + throw new RateLimitException(); + } + + return null; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..fe9d8e96 --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/utils/CookieUtil.java @@ -0,0 +1,42 @@ +package cn.lastwhisper.apigateway.utils; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Created by 廖师兄 + * 2018-03-04 23:25 + */ +public class CookieUtil { + + /** + * 设置cookie + * @param response + * @param name + * @param value + * @param maxAge + */ + public static void set(HttpServletResponse response, + String name, + String value, + int maxAge) { + Cookie cookie = new Cookie(name, value); + cookie.setPath("/"); + cookie.setMaxAge(maxAge); + response.addCookie(cookie); + } + + public static Cookie get(HttpServletRequest request, + String name) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie: cookies) { + if (name.equals(cookie.getName())) { + return cookie; + } + } + } + return null; + } +} 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/distributed/springcloud-netflix/api-gateway/src/test/java/cn/lastwhisper/apigateway/ApiGatewayApplicationTests.java b/distributed/springcloud-netflix/api-gateway/src/test/java/cn/lastwhisper/apigateway/ApiGatewayApplicationTests.java new file mode 100644 index 00000000..344ea7b3 --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/test/java/cn/lastwhisper/apigateway/ApiGatewayApplicationTests.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.apigateway; + +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApiGatewayApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/springcloud-netflix/client/pom.xml b/distributed/springcloud-netflix/client/pom.xml new file mode 100644 index 00000000..bb07a659 --- /dev/null +++ b/distributed/springcloud-netflix/client/pom.xml @@ -0,0 +1,115 @@ + + + 4.0.0 + + cn.lastwhisper + client + 0.0.1-SNAPSHOT + client + eureka client + + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + Finchley.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-web + 2.0.2.RELEASE + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.junit.jupiter + junit-jupiter-api + 5.5.2 + test + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + diff --git a/distributed/springcloud-netflix/client/src/main/java/cn/lastwhisper/client/ClientApplication.java b/distributed/springcloud-netflix/client/src/main/java/cn/lastwhisper/client/ClientApplication.java new file mode 100644 index 00000000..71b75d1a --- /dev/null +++ b/distributed/springcloud-netflix/client/src/main/java/cn/lastwhisper/client/ClientApplication.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; + +@SpringBootApplication +@EnableEurekaClient +//@EnableDiscoveryClient +public class ClientApplication { + + public static void main(String[] args) { + SpringApplication.run(ClientApplication.class, args); + } + +} diff --git a/distributed/springcloud-netflix/client/src/main/resources/application.yml b/distributed/springcloud-netflix/client/src/main/resources/application.yml new file mode 100644 index 00000000..c4fb36b2 --- /dev/null +++ b/distributed/springcloud-netflix/client/src/main/resources/application.yml @@ -0,0 +1,11 @@ +eureka: + client: + service-url: + defaultZone: http://localhost:8761/eureka/ +# instance: +# hostname: clientName +spring: + application: + name: client +server: + port: 8080 diff --git a/distributed/springcloud-netflix/client/src/test/java/cn/lastwhisper/client/ClientApplicationTests.java b/distributed/springcloud-netflix/client/src/test/java/cn/lastwhisper/client/ClientApplicationTests.java new file mode 100644 index 00000000..33660d16 --- /dev/null +++ b/distributed/springcloud-netflix/client/src/test/java/cn/lastwhisper/client/ClientApplicationTests.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.client; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ClientApplicationTests { + + @Test + void contextLoads() { + } + +} 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/distributed/springcloud-netflix/config/pom.xml b/distributed/springcloud-netflix/config/pom.xml new file mode 100644 index 00000000..df425f3a --- /dev/null +++ b/distributed/springcloud-netflix/config/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + cn.lastwhisper + config + 0.0.1-SNAPSHOT + config + 配置中心 + + + 1.8 + Finchley.RELEASE + + + + + org.springframework.cloud + spring-cloud-config-server + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + org.springframework.cloud + spring-cloud-starter-bus-amqp + + + + org.springframework.boot + spring-boot-starter-web + + + + 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 + + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + + diff --git a/distributed/springcloud-netflix/config/src/main/java/cn/lastwhisper/config/ConfigApplication.java b/distributed/springcloud-netflix/config/src/main/java/cn/lastwhisper/config/ConfigApplication.java new file mode 100644 index 00000000..d64abcc3 --- /dev/null +++ b/distributed/springcloud-netflix/config/src/main/java/cn/lastwhisper/config/ConfigApplication.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.config; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.config.server.EnableConfigServer; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableConfigServer +public class ConfigApplication { + + public static void main(String[] args) { + SpringApplication.run(ConfigApplication.class, args); + } + +} 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/distributed/springcloud-netflix/config/src/test/java/cn/lastwhisper/config/ConfigApplicationTests.java b/distributed/springcloud-netflix/config/src/test/java/cn/lastwhisper/config/ConfigApplicationTests.java new file mode 100644 index 00000000..92d1d2db --- /dev/null +++ b/distributed/springcloud-netflix/config/src/test/java/cn/lastwhisper/config/ConfigApplicationTests.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.config; + +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +public class ConfigApplicationTests { + + @Test + public void contextLoads() { + } + +} 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/distributed/springcloud-netflix/doc/springcloud.sql b/distributed/springcloud-netflix/doc/springcloud.sql new file mode 100644 index 00000000..44bc6d6d --- /dev/null +++ b/distributed/springcloud-netflix/doc/springcloud.sql @@ -0,0 +1,151 @@ +/* + Navicat Premium Data Transfer + + Source Server : localmysql5.7 + Source Server Type : MySQL + Source Server Version : 50724 + Source Host : localhost:3306 + Source Schema : springcloud + + Target Server Type : MySQL + Target Server Version : 50724 + File Encoding : 65001 + + Date: 07/11/2019 16:27:30 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for order_detail +-- ---------------------------- +DROP TABLE IF EXISTS `order_detail`; +CREATE TABLE `order_detail` ( + `detail_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `order_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `product_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `product_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '商品名称', + `product_price` decimal(8, 2) NOT NULL COMMENT '当前价格,单位分', + `product_quantity` int(11) NOT NULL COMMENT '数量', + `product_icon` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '小图', + `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间', + `update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间', + PRIMARY KEY (`detail_id`) USING BTREE, + INDEX `idx_order_id`(`order_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of order_detail +-- ---------------------------- +INSERT INTO `order_detail` VALUES ('12367', '123456', '157875196366160022', '皮蛋粥', 0.01, 2, 'http://xxx.com', '2019-10-26 18:50:01', '2019-10-26 18:50:01'); +INSERT INTO `order_detail` VALUES ('1572265264065159067', '1572265249230482564', '157875196366160022', '皮蛋粥', 0.01, 10, '//fuss10.elemecdn.com/0/49/65d10ef215d3c770ebb2b5ea962a7jpeg.jpeg', '2019-10-28 20:21:04', '2019-10-28 20:21:04'); +INSERT INTO `order_detail` VALUES ('1572422986230763715', '1572422985266920816', '157875196366160022', '皮蛋粥', 0.01, 10, '//fuss10.elemecdn.com/0/49/65d10ef215d3c770ebb2b5ea962a7jpeg.jpeg', '2019-10-30 16:09:46', '2019-10-30 16:09:46'); +INSERT INTO `order_detail` VALUES ('1572512779604627389', '1572512778632412686', '157875196366160022', '皮蛋粥', 0.01, 10, '//fuss10.elemecdn.com/0/49/65d10ef215d3c770ebb2b5ea962a7jpeg.jpeg', '2019-10-31 17:06:19', '2019-10-31 17:06:19'); +INSERT INTO `order_detail` VALUES ('1572515825124759977', '1572515806091648987', '157875196366160022', '皮蛋粥', 0.01, 10, '//fuss10.elemecdn.com/0/49/65d10ef215d3c770ebb2b5ea962a7jpeg.jpeg', '2019-10-31 17:57:05', '2019-10-31 17:57:05'); +INSERT INTO `order_detail` VALUES ('1572765129269206406', '1572765129256929590', '157875196366160022', '皮蛋粥', 0.01, 10, '//fuss10.elemecdn.com/0/49/65d10ef215d3c770ebb2b5ea962a7jpeg.jpeg', '2019-11-03 15:12:09', '2019-11-03 15:12:09'); +INSERT INTO `order_detail` VALUES ('1572766160158193310', '1572766160143206054', '157875196366160022', '皮蛋粥', 0.01, 10, '//fuss10.elemecdn.com/0/49/65d10ef215d3c770ebb2b5ea962a7jpeg.jpeg', '2019-11-03 15:29:20', '2019-11-03 15:29:20'); + +-- ---------------------------- +-- Table structure for order_master +-- ---------------------------- +DROP TABLE IF EXISTS `order_master`; +CREATE TABLE `order_master` ( + `order_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `buyer_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '买家名字', + `buyer_phone` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '买家电话', + `buyer_address` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '买家地址', + `buyer_openid` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '买家微信openid', + `order_amount` decimal(8, 2) NOT NULL COMMENT '订单总金额', + `order_status` tinyint(3) NOT NULL DEFAULT 0 COMMENT '订单状态, 默认为新下单', + `pay_status` tinyint(3) NOT NULL DEFAULT 0 COMMENT '支付状态, 默认未支付', + `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间', + `update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间', + PRIMARY KEY (`order_id`) USING BTREE, + INDEX `idx_buyer_openid`(`buyer_openid`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of order_master +-- ---------------------------- +INSERT INTO `order_master` VALUES ('1234567', '师兄', '1886131241241', '慕课网总部', '1101110', 2.50, 0, 0, '2019-10-26 18:47:15', '2019-10-26 18:47:15'); +INSERT INTO `order_master` VALUES ('1572230177079647461', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-10-28 10:36:17', '2019-10-28 10:36:17'); +INSERT INTO `order_master` VALUES ('1572230188817835247', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-10-28 10:36:28', '2019-10-28 10:36:28'); +INSERT INTO `order_master` VALUES ('1572264704845364768', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-10-28 20:11:46', '2019-10-28 20:11:46'); +INSERT INTO `order_master` VALUES ('1572264778893301261', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-10-28 20:12:58', '2019-10-28 20:12:58'); +INSERT INTO `order_master` VALUES ('1572264797691194132', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-10-28 20:13:17', '2019-10-28 20:13:17'); +INSERT INTO `order_master` VALUES ('1572265002884169673', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-10-28 20:16:42', '2019-10-28 20:16:42'); +INSERT INTO `order_master` VALUES ('1572265034382786927', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-10-28 20:18:24', '2019-10-28 20:18:24'); +INSERT INTO `order_master` VALUES ('1572265249230482564', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 1, 0, '2019-10-28 20:21:04', '2019-11-03 15:29:04'); +INSERT INTO `order_master` VALUES ('1572422985266920816', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-10-30 16:09:46', '2019-10-30 16:09:46'); +INSERT INTO `order_master` VALUES ('1572512778632412686', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-10-31 17:06:19', '2019-10-31 17:06:19'); +INSERT INTO `order_master` VALUES ('1572765129256929590', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-11-03 15:12:09', '2019-11-03 15:12:09'); +INSERT INTO `order_master` VALUES ('1572766160143206054', '张三', '18868822111', '慕课网总部', 'ew3euwhd7sjw9diwkq', 5499.00, 0, 0, '2019-11-03 15:29:20', '2019-11-03 15:29:20'); + +-- ---------------------------- +-- Table structure for product_category +-- ---------------------------- +DROP TABLE IF EXISTS `product_category`; +CREATE TABLE `product_category` ( + `category_id` int(11) NOT NULL AUTO_INCREMENT, + `category_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '类目名字', + `category_type` int(11) NOT NULL COMMENT '类目编号', + `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间', + `update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间', + PRIMARY KEY (`category_id`) USING BTREE, + UNIQUE INDEX `uqe_category_type`(`category_type`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of product_category +-- ---------------------------- +INSERT INTO `product_category` VALUES (1, '热榜', 1, '2017-03-28 16:40:22', '2019-10-26 16:08:28'); +INSERT INTO `product_category` VALUES (2, '好吃的', 2, '2017-03-14 17:38:46', '2019-10-26 16:08:32'); + +-- ---------------------------- +-- Table structure for product_info +-- ---------------------------- +DROP TABLE IF EXISTS `product_info`; +CREATE TABLE `product_info` ( + `product_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `product_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '商品名称', + `product_price` decimal(8, 2) NOT NULL COMMENT '单价', + `product_stock` int(11) NOT NULL COMMENT '库存', + `product_description` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述', + `product_icon` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '小图', + `product_status` tinyint(3) NULL DEFAULT 0 COMMENT '商品状态,0正常1下架', + `category_type` int(11) NOT NULL COMMENT '类目编号', + `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间', + `update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间', + PRIMARY KEY (`product_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of product_info +-- ---------------------------- +INSERT INTO `product_info` VALUES ('157875196366160022', '皮蛋粥', 0.01, 12860, '好吃的皮蛋粥', '//fuss10.elemecdn.com/0/49/65d10ef215d3c770ebb2b5ea962a7jpeg.jpeg', 0, 1, '2017-03-28 19:39:15', '2019-10-31 17:56:40'); +INSERT INTO `product_info` VALUES ('157875227953464068', '慕斯蛋糕', 10.90, 18300, '美味爽口', '//fuss10.elemecdn.com/9/93/91994e8456818dfe7b0bd95f10a50jpeg.jpeg', 1, 1, '2017-03-28 19:35:54', '2019-10-31 17:56:40'); +INSERT INTO `product_info` VALUES ('164103465734242707', '蜜汁鸡翅', 0.02, 98200, '好吃', '//fuss10.elemecdn.com/7/4a/f307f56216b03f067155aec8b124ejpeg.jpeg', 0, 1, '2017-03-30 17:11:56', '2019-10-31 17:56:40'); + +-- ---------------------------- +-- Table structure for user_info +-- ---------------------------- +DROP TABLE IF EXISTS `user_info`; +CREATE TABLE `user_info` ( + `id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '', + `password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '', + `openid` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '微信openid', + `role` tinyint(1) NOT NULL COMMENT '1买家2卖家', + `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间', + `update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of user_info +-- ---------------------------- +INSERT INTO `user_info` VALUES ('1', '', '', 'abc', 1, '2019-11-03 09:00:52', '2019-11-03 09:00:52'); +INSERT INTO `user_info` VALUES ('2', '', '', 'xyz', 2, '2019-11-03 09:00:58', '2019-11-03 09:00:58'); + +SET FOREIGN_KEY_CHECKS = 1; 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/distributed/springcloud-netflix/eureka/pom.xml b/distributed/springcloud-netflix/eureka/pom.xml new file mode 100644 index 00000000..3c65847e --- /dev/null +++ b/distributed/springcloud-netflix/eureka/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + cn.lastwhisper + eureka + 0.0.1-SNAPSHOT + eureka + eureka server + + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + Finchley.RELEASE + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.junit.jupiter + junit-jupiter-api + 5.5.2 + test + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/springcloud-netflix/eureka/src/main/java/cn/lastwhisper/eureka/EurekaApplication.java b/distributed/springcloud-netflix/eureka/src/main/java/cn/lastwhisper/eureka/EurekaApplication.java new file mode 100644 index 00000000..0f4f7f31 --- /dev/null +++ b/distributed/springcloud-netflix/eureka/src/main/java/cn/lastwhisper/eureka/EurekaApplication.java @@ -0,0 +1,15 @@ +package cn.lastwhisper.eureka; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +@SpringBootApplication +@EnableEurekaServer +public class EurekaApplication { + + public static void main(String[] args) { + SpringApplication.run(EurekaApplication.class, args); + } + +} diff --git a/distributed/springcloud-netflix/eureka/src/main/resources/application.yml b/distributed/springcloud-netflix/eureka/src/main/resources/application.yml new file mode 100644 index 00000000..cb14a669 --- /dev/null +++ b/distributed/springcloud-netflix/eureka/src/main/resources/application.yml @@ -0,0 +1,14 @@ +server: + port: 8761 +spring: + application: + name: eureka +eureka: + client: + service-url: + defaultZone: http://localhost:8761/eureka/ #配置HA互相注册 + register-with-eureka: false + #关闭eureka的自我保护功能 + server: + enable-self-preservation: false + diff --git a/distributed/springcloud-netflix/eureka/src/test/java/cn/lastwhisper/eureka/EurekaApplicationTests.java b/distributed/springcloud-netflix/eureka/src/test/java/cn/lastwhisper/eureka/EurekaApplicationTests.java new file mode 100644 index 00000000..bd2a2bd5 --- /dev/null +++ b/distributed/springcloud-netflix/eureka/src/test/java/cn/lastwhisper/eureka/EurekaApplicationTests.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.eureka; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class EurekaApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/springcloud-netflix/order-old/pom.xml b/distributed/springcloud-netflix/order-old/pom.xml new file mode 100644 index 00000000..db588ee7 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/pom.xml @@ -0,0 +1,141 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + cn.lastwhisper + order-old + 0.0.1-SNAPSHOT + order-old + 订单服务 + + + 1.8 + Finchley.RELEASE + + + + + 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.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + junit + junit + 4.12 + test + + + + + mysql + mysql-connector-java + runtime + + + + org.projectlombok + lombok + true + + + + com.google.code.gson + gson + 2.8.6 + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + diff --git a/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/OrderApplication.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/OrderApplication.java new file mode 100644 index 00000000..b610121f --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/OrderApplication.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.order; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; + +/** + * @author Administrator + */ +@SpringBootApplication +@EnableDiscoveryClient +@EnableFeignClients +public class OrderApplication { + + public static void main(String[] args) { + SpringApplication.run(OrderApplication.class, args); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d8368954 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/client/ProductClient.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.order.client; + +import cn.lastwhisper.order.domain.ProductInfo; +import cn.lastwhisper.order.dto.CartDTO; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@FeignClient("product") +public interface ProductClient { + + @GetMapping("/msg") + public String productMsg(); + + @PostMapping("/product/listForOrder") + public List listForOrder(@RequestBody List productIdList); + + @PostMapping("/product/decreaseStock") + public void decreaseStock(@RequestBody List cartDTOList); +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..5a912840 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/conf/RestTemplateConfig.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.order.conf; + +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +/** + * @author lastwhisper + * @date 2019/10/28 + */ +//@Component +public class RestTemplateConfig { + + @Bean + @LoadBalanced + public RestTemplate restTemplate(){ + return new RestTemplate(); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..8a356709 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java @@ -0,0 +1,49 @@ +package cn.lastwhisper.order.controller; + +import cn.lastwhisper.order.client.ProductClient; +import cn.lastwhisper.order.domain.ProductInfo; +import cn.lastwhisper.order.dto.CartDTO; +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.RestController; + +import java.util.Arrays; +import java.util.List; + +/** + * feign调用 + * @author lastwhisper + * @date 2019/10/28 + */ +@RestController +@Slf4j +public class FeignClientController { + + + @Autowired + private ProductClient productClient; + + @GetMapping("/getProductMsg") + public String getProductMsg() { + + String response = productClient.productMsg(); + log.info("response={}", response); + return response; + } + + @GetMapping("/getProductList") + public List getProductList() { + List productInfoList = productClient.listForOrder(Arrays.asList("157875196366160022")); + log.info("response={}", productInfoList); + return productInfoList; + } + + @GetMapping("/decreaseStock") + public String decreaseStock() { + CartDTO cartDTO = new CartDTO("157875227953464068", 7); + productClient.decreaseStock(Arrays.asList(cartDTO)); + return "ok"; + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..7357a41f --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/controller/OrderController.java @@ -0,0 +1,71 @@ +package cn.lastwhisper.order.controller; + +import cn.lastwhisper.order.convert.OrderForm2OrderDTOConvert; +import cn.lastwhisper.order.domain.ProductInfo; +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.RestController; + +import javax.validation.Valid; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 订单 + * @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(), + 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); + + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..eed0c41f --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/controller/RestTemplateClientController.java @@ -0,0 +1,52 @@ +package cn.lastwhisper.order.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +/** + * RestTemplate调用三种使用方式 + * @author lastwhisper + * @date 2019/10/28 + */ +//@RestController +@Slf4j +public class RestTemplateClientController { + + + @Autowired + private LoadBalancerClient loadBalancerClient; + + + //@Autowired + //private RestTemplate restTemplate; + + @GetMapping("/getProductMsg") + public String getProductMsg() { + + // 1.url硬编码,实际部署时可能不知道其他应用的ip, + // 且当一个应用有多个实例时会很麻烦 + //RestTemplate restTemplate = new RestTemplate(); + //String url = "http://localhost:8080/msg"; + //String response = restTemplate.getForObject(url, String.class); + + // 2.loadBalancerClient根据应用名称获取url + ServiceInstance product = loadBalancerClient.choose("PRODUCT"); + String url = String.format("http://%s:%s", product.getHost(), product.getPort() + "/msg"); + RestTemplate restTemplate = new RestTemplate(); + String response = restTemplate.getForObject(url, String.class); + + // 3. 使用@Bean+注解 + //String url = "http://PRODUCT/msg"; + //String response = restTemplate.getForObject(url, String.class); + + log.info("url={},response={}", url, response); + + return response; + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..57e82926 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/convert/OrderForm2OrderDTOConvert.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.order.convert; + +import cn.lastwhisper.order.domain.OrderDetail; +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 com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * @author lastwhisper + * @date 2019/10/28 + */ +@Slf4j +public class OrderForm2OrderDTOConvert { + + public static OrderDTO convert(OrderForm orderForm) { + OrderDTO orderDTO = new OrderDTO(); + orderDTO.setBuyerName(orderForm.getName()); + orderDTO.setBuyerPhone(orderForm.getPhone()); + orderDTO.setBuyerAddress(orderForm.getAddress()); + orderDTO.setBuyerOpenid(orderForm.getOpenid()); + + List orderDetailList = null; + Gson gson = new Gson(); + + try { + orderDetailList = gson.fromJson(orderForm.getItems(), + new TypeToken>() { + }.getType()); + } catch (Exception e) { + log.error("【json转换】错误, string={}", orderForm.getItems()); + // throw new OrderException(ResultEnum.PARAM_ERROR.getMsg(), ResultEnum.PARAM_ERROR.getCode()); + throw new OrderException(ResultEnum.PARAM_ERROR); + } + orderDTO.setOrderDetailList(orderDetailList); + + return orderDTO; + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..9e8c21e7 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/domain/OrderDetail.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.order.domain; + +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Entity; +import javax.persistence.Id; +import java.math.BigDecimal; + +/** + * 2017-12-10 16:07 + * @author Administrator + */ +@Getter +@Setter +@Entity +public class OrderDetail { + + @Id + private String detailId; + + /** 订单id. */ + private String orderId; + + /** 商品id. */ + private String productId; + + /** 商品名称. */ + private String productName; + + /** 商品单价. */ + private BigDecimal productPrice; + + /** 商品数量. */ + private Integer productQuantity; + + /** 商品小图. */ + private String productIcon; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..a6b3626f --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/domain/OrderMaster.java @@ -0,0 +1,51 @@ +package cn.lastwhisper.order.domain; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Entity; +import javax.persistence.Id; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 2017-12-10 16:06 + * @author Administrator + */ +@Getter +@Setter +@Entity +public class OrderMaster { + + /** 订单id. */ + @Id + private String orderId; + + /** 买家名字. */ + private String buyerName; + + /** 买家手机号. */ + private String buyerPhone; + + /** 买家地址. */ + private String buyerAddress; + + /** 买家微信Openid. */ + private String buyerOpenid; + + /** 订单总金额. */ + private BigDecimal orderAmount; + + /** 订单状态, 默认为0新下单. */ + private Integer orderStatus; + + /** 支付状态, 默认为0未支付. */ + private Integer payStatus; + + /** 创建时间. */ + private Date createTime; + + /** 更新时间. */ + private Date updateTime; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..71485293 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/domain/ProductInfo.java @@ -0,0 +1,53 @@ +package cn.lastwhisper.order.domain; + +import lombok.*; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.math.BigDecimal; +import java.util.Date; + +/** + * product_info表对应的实体类 + * @author lastwhisper + * @date 2019/10/24 + */ +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +@Entity +@Table(name = "product_info") +public class ProductInfo { + + @Id + private String productId; + + /** 名字. */ + private String productName; + + /** 单价. */ + private BigDecimal productPrice; + + /** 库存. */ + private Integer productStock; + + /** 描述. */ + private String productDescription; + + /** 小图. */ + private String productIcon; + + /** 状态, 0正常1下架. */ + private Integer productStatus; + + /** 类目编号. */ + private Integer categoryType; + + private Date createTime; + + private Date updateTime; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..e0364132 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/dto/CartDTO.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.order.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class CartDTO { + + private String productId; + + private Integer productQuantity; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..da83e8d2 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/dto/OrderDTO.java @@ -0,0 +1,47 @@ +package cn.lastwhisper.order.dto; + +import cn.lastwhisper.order.domain.OrderDetail; +import lombok.Getter; +import lombok.Setter; + +import java.math.BigDecimal; +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +public class OrderDTO { + + /** 订单id. */ + private String orderId; + + /** 买家名字. */ + private String buyerName; + + /** 买家手机号. */ + private String buyerPhone; + + /** 买家地址. */ + private String buyerAddress; + + /** 买家微信Openid. */ + private String buyerOpenid; + + /** 订单总金额. */ + private BigDecimal orderAmount; + + /** 订单状态, 默认为0新下单. */ + private Integer orderStatus; + + /** 支付状态, 默认为0未支付. */ + private Integer payStatus; + + private List orderDetailList; + +} + + diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..fbc506e5 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/enums/OrderStatusEnum.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.order.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 订单状态枚举 + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@AllArgsConstructor +public enum OrderStatusEnum { + /** + * 新订单 + */ + NEW(0,"新订单"), + /** + * 订单完结 + */ + FINISHED(1,"完结"), + /** + * 订单取消 + */ + CANCEL(2,"取消"); + private Integer code; + + private String message; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..b88ceede --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/enums/PayStatusEnum.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.order.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +/** + * 支付状态枚举 + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@AllArgsConstructor +public enum PayStatusEnum { + /** + * 等待支付 + */ + WAIT(0, "等待支付"), + /** + * 支付成功 + */ + SUCCESS(1, "支付成功"), + ; + private Integer code; + + private String message; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..3841a383 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/enums/ResultEnum.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.order.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 返回错误结果枚举 + * @author lastwhisper + * @date 2019/10/28 + */ +@AllArgsConstructor +@Getter +public enum ResultEnum { + /*参数错误枚举*/ + PARAM_ERROR(1,"参数错误"), + CART_EMPTY(2,"购物车为空") + ; + + private Integer code; + private String msg; + + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..5483e8d3 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/exception/OrderException.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.order.exception; + +import cn.lastwhisper.order.enums.ResultEnum; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +public class OrderException extends RuntimeException { + + private Integer code; + + public OrderException(Integer code,String message ) { + super(message); + this.code = code; + } + + public OrderException(ResultEnum resultEnum) { + this(resultEnum.getCode(),resultEnum.getMsg()); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d2f50079 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/form/OrderForm.java @@ -0,0 +1,47 @@ +package cn.lastwhisper.order.form; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotEmpty; + +/** + * 创建订单接口入参 + * @author lastwhisper + * @date 2019/10/27 + */ +@Getter +@Setter +public class OrderForm { + + /** + * 买家姓名 + */ + @NotEmpty(message = "姓名必填") + private String name; + + /** + * 买家手机号 + */ + @NotEmpty(message = "手机号必填") + private String phone; + + /** + * 买家地址 + */ + @NotEmpty(message = "地址必填") + private String address; + + /** + * 买家微信openid + */ + @NotEmpty(message = "openid必填") + private String openid; + + /** + * 购物车 + */ + @NotEmpty(message = "购物车不能为空") + private String items; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..8b43f187 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/repository/OrderDetailRepository.java @@ -0,0 +1,10 @@ +package cn.lastwhisper.order.repository; + +import cn.lastwhisper.order.domain.OrderDetail; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @author lastwhisper + */ +public interface OrderDetailRepository extends JpaRepository { +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..f2a44f7f --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/repository/OrderMasterRepository.java @@ -0,0 +1,12 @@ +package cn.lastwhisper.order.repository; + +import cn.lastwhisper.order.domain.OrderMaster; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +public interface OrderMasterRepository extends JpaRepository { +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..9321ae62 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/service/OrderService.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.order.service; + +import cn.lastwhisper.order.dto.OrderDTO; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +public interface OrderService { + + public OrderDTO create(OrderDTO orderDTO); + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..14f40b01 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java @@ -0,0 +1,85 @@ +package cn.lastwhisper.order.service.impl; + +import cn.lastwhisper.order.client.ProductClient; +import cn.lastwhisper.order.domain.OrderDetail; +import cn.lastwhisper.order.domain.OrderMaster; +import cn.lastwhisper.order.domain.ProductInfo; +import cn.lastwhisper.order.dto.CartDTO; +import cn.lastwhisper.order.dto.OrderDTO; +import cn.lastwhisper.order.enums.OrderStatusEnum; +import cn.lastwhisper.order.enums.PayStatusEnum; +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 org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; +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 + 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 (ProductInfo 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 cartDTOList = orderDTO.getOrderDetailList().stream() + .map(o->new CartDTO(o.getProductId(),o.getProductQuantity())) + .collect(Collectors.toList()); + productClient.decreaseStock(cartDTOList); + // 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; + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..7c4f34de --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/utils/KeyUtil.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.order.utils; + +import java.util.Random; + +/** + * Created by 廖师兄 + * 2017-12-10 16:57 + */ +public class KeyUtil { + + /** + * 生成唯一的主键 + * 格式: 时间+随机数 + */ + public static synchronized String genUniqueKey() { + Random random = new Random(); + Integer number = random.nextInt(900000) + 100000; + + return System.currentTimeMillis() + String.valueOf(number); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..752d345f --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/utils/ResultVOUtil.java @@ -0,0 +1,19 @@ +package cn.lastwhisper.order.utils; + + +import cn.lastwhisper.order.vo.ResultVO; + +/** + * Created by 廖师兄 + * 2017-12-10 18:03 + */ +public class ResultVOUtil { + + public static ResultVO success(Object object) { + ResultVO resultVO = new ResultVO(); + resultVO.setCode(0); + resultVO.setMsg("成功"); + resultVO.setData(object); + return resultVO; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..ae016453 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/vo/ResultVO.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.order.vo; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * http响应最外层数据 + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +@NoArgsConstructor +public class ResultVO { + /** + * 响应码 + */ + private Integer code; + /** + * 响应消息 + */ + private String msg; + /** + * 响应内容 + */ + private T data; +} diff --git a/distributed/springcloud-netflix/order-old/src/main/resources/application.yml b/distributed/springcloud-netflix/order-old/src/main/resources/application.yml new file mode 100644 index 00000000..6dd3d2a5 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/main/resources/application.yml @@ -0,0 +1,16 @@ +spring: + application: + name: order + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/springcloud?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false + username: root + password: root + jpa: + show-sql: true +eureka: + client: + service-url: + defaultZone: http://localhost:8761/eureka/ +server: + port: 8081 \ No newline at end of file diff --git a/distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java b/distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java new file mode 100644 index 00000000..7848dfd0 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.order; + +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +public class OrderApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..cbafedc6 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/repository/OrderDetailRepositoryTest.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.order.repository; + +import cn.lastwhisper.order.OrderApplicationTests; +import cn.lastwhisper.order.domain.OrderDetail; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.math.BigDecimal; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +public class OrderDetailRepositoryTest extends OrderApplicationTests { + + @Autowired + private OrderDetailRepository orderDetailRepository; + + @Test + public void testSave() { + OrderDetail orderDetail = new OrderDetail(); + orderDetail.setDetailId("12367"); + orderDetail.setOrderId("123456"); + orderDetail.setProductIcon("http://xxx.com"); + orderDetail.setProductId("157875196366160022"); + orderDetail.setProductName("皮蛋粥"); + orderDetail.setProductPrice(new BigDecimal(0.01)); + orderDetail.setProductQuantity(2); + + OrderDetail result = orderDetailRepository.save(orderDetail); + Assert.assertTrue(result != null); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..74c7e482 --- /dev/null +++ b/distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/repository/OrderMasterRepositoryTest.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.order.repository; + + +import cn.lastwhisper.order.OrderApplicationTests; +import cn.lastwhisper.order.domain.OrderMaster; +import cn.lastwhisper.order.enums.OrderStatusEnum; +import cn.lastwhisper.order.enums.PayStatusEnum; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.math.BigDecimal; + +public class OrderMasterRepositoryTest extends OrderApplicationTests { + + @Autowired + private OrderMasterRepository orderMasterRepository; + + @Test + public void testSave() { + OrderMaster orderMaster = new OrderMaster(); + orderMaster.setOrderId("1234567"); + orderMaster.setBuyerName("师兄"); + orderMaster.setBuyerPhone("1886131241241"); + orderMaster.setBuyerAddress("慕课网总部"); + orderMaster.setBuyerOpenid("1101110"); + orderMaster.setOrderAmount(new BigDecimal(2.5)); + orderMaster.setOrderStatus(OrderStatusEnum.NEW.getCode()); + orderMaster.setPayStatus(PayStatusEnum.WAIT.getCode()); + + OrderMaster result = orderMasterRepository.save(orderMaster); + Assert.assertTrue(result != null); + } + +} \ No newline at end of file diff --git a/distributed/springcloud-netflix/order/order-client/pom.xml b/distributed/springcloud-netflix/order/order-client/pom.xml new file mode 100644 index 00000000..c3e1b6d6 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-client/pom.xml @@ -0,0 +1,22 @@ + + + + order + cn.lastwhisper + 0.0.1-SNAPSHOT + + 4.0.0 + + order-client + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + \ No newline at end of file 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/distributed/springcloud-netflix/order/order-common/pom.xml b/distributed/springcloud-netflix/order/order-common/pom.xml new file mode 100644 index 00000000..bb3a83f7 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-common/pom.xml @@ -0,0 +1,22 @@ + + + + order + cn.lastwhisper + 0.0.1-SNAPSHOT + + 4.0.0 + + order-common + + + + + org.projectlombok + lombok + + + + \ No newline at end of file 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/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..ef234408 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/OrderApplication.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.order; + +import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.cloud.client.SpringCloudApplication; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; + +/** + * @author Administrator + */ +@EnableFeignClients(basePackages = "cn.lastwhisper.product.client") +//@SpringBootApplication +//@EnableDiscoveryClient +//@EnableCircuitBreaker +@SpringCloudApplication +@EnableHystrixDashboard +public class OrderApplication { + + public static void main(String[] args) { + SpringApplication.run(OrderApplication.class, args); + } + + @Bean + public ServletRegistrationBean getServlet(){ + HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet(); + ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); + registrationBean.setLoadOnStartup(1); + registrationBean.addUrlMappings("/hystrix.stream");/*/actuator/hystrix.stream*/ + registrationBean.setName("HystrixMetricsStreamServlet"); + return registrationBean; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..5cd5c910 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/conf/RestTemplateConfig.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.order.conf; + +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +/** + * @author lastwhisper + * @date 2019/10/28 + */ +//@Component +public class RestTemplateConfig { + + @Bean + @LoadBalanced + public RestTemplate restTemplate(){ + return new RestTemplate(); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..cc3058fe --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/EnvController.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.order.controller; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 测试SpringCloud 配置中心客户端 + */ +@RestController +@RequestMapping("/env") +@RefreshScope +public class EnvController { + + @Value("${env}") + private String env; + + @GetMapping("/print") + public String print() { + return env; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..8eb3daf5 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java @@ -0,0 +1,57 @@ +package cn.lastwhisper.order.controller; + +import cn.lastwhisper.product.client.ProductClient; +import cn.lastwhisper.product.common.DecreaseStockInput; +import cn.lastwhisper.product.common.ProductInfoOutput; +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; +import java.util.List; + +/** + * feign调用 + * @author lastwhisper + * @date 2019/10/28 + */ +@RestController +@Slf4j +public class FeignClientController { + + @Autowired + private ProductClient productClient; + + @GetMapping("/getProductMsg") + public String getProductMsg() { + + String response = productClient.productMsg(); + log.info("response={}", response); + return response; + } + + @GetMapping("/getProductList") + public List getProductList() { + List productInfoList = productClient.listForOrder(Arrays.asList("157875196366160022")); + log.info("response={}", productInfoList); + return productInfoList; + } + + @GetMapping("/decreaseStock") + public String decreaseStock() { + //CartDTO cartDTO = new CartDTO("157875227953464068", 7); + DecreaseStockInput decreaseStockInput = new DecreaseStockInput("157875227953464068", 7); + productClient.decreaseStock(Arrays.asList(decreaseStockInput)); + 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/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..3f57f2b8 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/RestTemplateClientController.java @@ -0,0 +1,51 @@ +package cn.lastwhisper.order.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.client.RestTemplate; + +/** + * RestTemplate调用三种使用方式 + * @author lastwhisper + * @date 2019/10/28 + */ +//@RestController +@Slf4j +public class RestTemplateClientController { + + + @Autowired + private LoadBalancerClient loadBalancerClient; + + + //@Autowired + //private RestTemplate restTemplate; + + @GetMapping("/getProductMsg") + public String getProductMsg() { + + // 1.url硬编码,实际部署时可能不知道其他应用的ip, + // 且当一个应用有多个实例时会很麻烦 + //RestTemplate restTemplate = new RestTemplate(); + //String url = "http://localhost:8080/msg"; + //String response = restTemplate.getForObject(url, String.class); + + // 2.loadBalancerClient根据应用名称获取url + ServiceInstance product = loadBalancerClient.choose("PRODUCT"); + String url = String.format("http://%s:%s", product.getHost(), product.getPort() + "/msg"); + RestTemplate restTemplate = new RestTemplate(); + String response = restTemplate.getForObject(url, String.class); + + // 3. 使用@Bean+注解 + //String url = "http://PRODUCT/msg"; + //String response = restTemplate.getForObject(url, String.class); + + log.info("url={},response={}", url, response); + + return response; + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..e33160c4 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/SendMessageController.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.order.controller; + +import cn.lastwhisper.order.dto.OrderDTO; +import cn.lastwhisper.order.message.StreamClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; + +/** + * springcloud stream rabbitmq 消息发送方 + * @author lastwhisper + * @date 2019/10/31 + */ +//@RestController +public class SendMessageController { + + @Autowired + private StreamClient streamClient; + + @GetMapping("/sendMessage") + public void process() { + String message = "now " + new Date(); + streamClient.output().send(MessageBuilder.withPayload(message).build()); + } + + //@GetMapping("/sendObject") + //public void process2() { + // OrderDTO orderDTO = new OrderDTO(); + // orderDTO.setBuyerOpenid("123456789"); + // orderDTO.setBuyerAddress("北京昌平"); + // streamClient.output().send(MessageBuilder.withPayload(orderDTO).build()); + //} +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..57e82926 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/convert/OrderForm2OrderDTOConvert.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.order.convert; + +import cn.lastwhisper.order.domain.OrderDetail; +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 com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * @author lastwhisper + * @date 2019/10/28 + */ +@Slf4j +public class OrderForm2OrderDTOConvert { + + public static OrderDTO convert(OrderForm orderForm) { + OrderDTO orderDTO = new OrderDTO(); + orderDTO.setBuyerName(orderForm.getName()); + orderDTO.setBuyerPhone(orderForm.getPhone()); + orderDTO.setBuyerAddress(orderForm.getAddress()); + orderDTO.setBuyerOpenid(orderForm.getOpenid()); + + List orderDetailList = null; + Gson gson = new Gson(); + + try { + orderDetailList = gson.fromJson(orderForm.getItems(), + new TypeToken>() { + }.getType()); + } catch (Exception e) { + log.error("【json转换】错误, string={}", orderForm.getItems()); + // throw new OrderException(ResultEnum.PARAM_ERROR.getMsg(), ResultEnum.PARAM_ERROR.getCode()); + throw new OrderException(ResultEnum.PARAM_ERROR); + } + orderDTO.setOrderDetailList(orderDetailList); + + return orderDTO; + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..9e8c21e7 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/domain/OrderDetail.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.order.domain; + +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Entity; +import javax.persistence.Id; +import java.math.BigDecimal; + +/** + * 2017-12-10 16:07 + * @author Administrator + */ +@Getter +@Setter +@Entity +public class OrderDetail { + + @Id + private String detailId; + + /** 订单id. */ + private String orderId; + + /** 商品id. */ + private String productId; + + /** 商品名称. */ + private String productName; + + /** 商品单价. */ + private BigDecimal productPrice; + + /** 商品数量. */ + private Integer productQuantity; + + /** 商品小图. */ + private String productIcon; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..eb5fd577 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/domain/OrderMaster.java @@ -0,0 +1,50 @@ +package cn.lastwhisper.order.domain; + +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Entity; +import javax.persistence.Id; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 2017-12-10 16:06 + * @author Administrator + */ +@Getter +@Setter +@Entity +public class OrderMaster { + + /** 订单id. */ + @Id + private String orderId; + + /** 买家名字. */ + private String buyerName; + + /** 买家手机号. */ + private String buyerPhone; + + /** 买家地址. */ + private String buyerAddress; + + /** 买家微信Openid. */ + private String buyerOpenid; + + /** 订单总金额. */ + private BigDecimal orderAmount; + + /** 订单状态, 默认为0新下单. */ + private Integer orderStatus; + + /** 支付状态, 默认为0未支付. */ + private Integer payStatus; + + /** 创建时间. */ + private Date createTime; + + /** 更新时间. */ + private Date updateTime; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..71485293 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/domain/ProductInfo.java @@ -0,0 +1,53 @@ +package cn.lastwhisper.order.domain; + +import lombok.*; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.math.BigDecimal; +import java.util.Date; + +/** + * product_info表对应的实体类 + * @author lastwhisper + * @date 2019/10/24 + */ +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +@Entity +@Table(name = "product_info") +public class ProductInfo { + + @Id + private String productId; + + /** 名字. */ + private String productName; + + /** 单价. */ + private BigDecimal productPrice; + + /** 库存. */ + private Integer productStock; + + /** 描述. */ + private String productDescription; + + /** 小图. */ + private String productIcon; + + /** 状态, 0正常1下架. */ + private Integer productStatus; + + /** 类目编号. */ + private Integer categoryType; + + private Date createTime; + + private Date updateTime; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..e0364132 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/dto/CartDTO.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.order.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class CartDTO { + + private String productId; + + private Integer productQuantity; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..da83e8d2 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/dto/OrderDTO.java @@ -0,0 +1,47 @@ +package cn.lastwhisper.order.dto; + +import cn.lastwhisper.order.domain.OrderDetail; +import lombok.Getter; +import lombok.Setter; + +import java.math.BigDecimal; +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +public class OrderDTO { + + /** 订单id. */ + private String orderId; + + /** 买家名字. */ + private String buyerName; + + /** 买家手机号. */ + private String buyerPhone; + + /** 买家地址. */ + private String buyerAddress; + + /** 买家微信Openid. */ + private String buyerOpenid; + + /** 订单总金额. */ + private BigDecimal orderAmount; + + /** 订单状态, 默认为0新下单. */ + private Integer orderStatus; + + /** 支付状态, 默认为0未支付. */ + private Integer payStatus; + + private List orderDetailList; + +} + + diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..fbc506e5 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/enums/OrderStatusEnum.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.order.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 订单状态枚举 + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@AllArgsConstructor +public enum OrderStatusEnum { + /** + * 新订单 + */ + NEW(0,"新订单"), + /** + * 订单完结 + */ + FINISHED(1,"完结"), + /** + * 订单取消 + */ + CANCEL(2,"取消"); + private Integer code; + + private String message; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..ab0bba00 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/enums/PayStatusEnum.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.order.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 支付状态枚举 + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@AllArgsConstructor +public enum PayStatusEnum { + /** + * 等待支付 + */ + WAIT(0, "等待支付"), + /** + * 支付成功 + */ + SUCCESS(1, "支付成功"), + ; + private Integer code; + + private String message; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..3418ea12 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/enums/ResultEnum.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.order.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 返回错误结果枚举 + * @author lastwhisper + * @date 2019/10/28 + */ +@AllArgsConstructor +@Getter +public enum ResultEnum { + /*参数错误枚举*/ + PARAM_ERROR(1,"参数错误"), + CART_EMPTY(2,"购物车为空"), + ORDER_NOT_EXIST(3,"订单不存在"), + ORDER_STATUS_ERROR(4,"订单状态错误"), + ORDER_DETAIL_NOT_EXIST(5,"订单详情不存在") + ; + + private Integer code; + private String msg; + + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..5483e8d3 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/exception/OrderException.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.order.exception; + +import cn.lastwhisper.order.enums.ResultEnum; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +public class OrderException extends RuntimeException { + + private Integer code; + + public OrderException(Integer code,String message ) { + super(message); + this.code = code; + } + + public OrderException(ResultEnum resultEnum) { + this(resultEnum.getCode(),resultEnum.getMsg()); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d2f50079 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/form/OrderForm.java @@ -0,0 +1,47 @@ +package cn.lastwhisper.order.form; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotEmpty; + +/** + * 创建订单接口入参 + * @author lastwhisper + * @date 2019/10/27 + */ +@Getter +@Setter +public class OrderForm { + + /** + * 买家姓名 + */ + @NotEmpty(message = "姓名必填") + private String name; + + /** + * 买家手机号 + */ + @NotEmpty(message = "手机号必填") + private String phone; + + /** + * 买家地址 + */ + @NotEmpty(message = "地址必填") + private String address; + + /** + * 买家微信openid + */ + @NotEmpty(message = "openid必填") + private String openid; + + /** + * 购物车 + */ + @NotEmpty(message = "购物车不能为空") + private String items; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d67e91fe --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/AmqpReceiver.java @@ -0,0 +1,57 @@ +package cn.lastwhisper.order.message; + +import lombok.extern.slf4j.Slf4j; +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.RabbitListener; +import org.springframework.stereotype.Component; + +/** + * 接收MQ的消息 + * @author lastwhisper + * @date 2019/10/31 + */ +@Slf4j +//@Component +public class AmqpReceiver { + /** + * 1.手动创建队列 @RabbitListener(queues = "myQueue") + * 2.自动创建队列 @RabbitListener(queuesToDeclare = @Queue("myQueue")) + * 3.自动创建Exchange与Queue绑定 + */ + @RabbitListener(bindings = @QueueBinding( + value = @Queue("myQueue"), + exchange = @Exchange("myExchange") + )) + public void process(String message) { + log.info("MqReceiver={}", message); + } + + /** + * 数码供应商服务 接收消息 + * @param message + */ + @RabbitListener(bindings = @QueueBinding( + exchange = @Exchange("myOrder"), + key = "computer", + value = @Queue("computerOrder") + )) + public void processComputer(String message) { + log.info("computer MqReceiver: {}", message); + } + + + /** + * 水果供应商服务 接收消息 + * @param message + */ + @RabbitListener(bindings = @QueueBinding( + exchange = @Exchange("myOrder"), + key = "fruit", + value = @Queue("fruitOrder") + )) + public void processFruit(String message) { + log.info("fruit MqReceiver: {}", message); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..346243de --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/ProductInfoReceiver.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.order.message; + +import cn.lastwhisper.order.utils.JsonUtil; +import cn.lastwhisper.product.common.ProductInfoOutput; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.annotation.Queue; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/31 + */ +//@Component +@Slf4j +public class ProductInfoReceiver { + + private static final String PRODUCT_STOCK_TEMPLATE = "product_stock_%s"; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @RabbitListener(queuesToDeclare = @Queue("productInfo")) + public void process(String message) { + List productInfoOutputList = (List) JsonUtil.fromJson(message, + new TypeReference>() { + }); + 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/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..7729e329 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/StreamClient.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.order.message; + +import org.springframework.cloud.stream.annotation.Input; +import org.springframework.cloud.stream.annotation.Output; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.SubscribableChannel; + +/** + * + * @author lastwhisper + * @date 2019/10/31 + */ +public interface StreamClient { + + String INPUT = "myMessage"; + + String INPUT2 = "myMessage2"; + + @Input(StreamClient.INPUT) + SubscribableChannel input(); + + @Output(StreamClient.INPUT2) + MessageChannel output(); + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..90a71233 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/StreamReceiver.java @@ -0,0 +1,40 @@ +package cn.lastwhisper.order.message; + +import cn.lastwhisper.order.dto.OrderDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.handler.annotation.SendTo; +import org.springframework.stereotype.Component; + +/** + * springcloud stream rabbitmq 消息接收方 + * @author lastwhisper + * @date 2019/10/31 + */ +//@Component +//@EnableBinding(StreamClient.class) +@Slf4j +public class StreamReceiver { + + @StreamListener(value = StreamClient.INPUT) + public void process(Object message) { + log.info("StreamReceiver: {}", message); + } + + /** + * 接收orderDTO对象 消息 + * @param message + */ + @StreamListener(value = StreamClient.INPUT) + @SendTo(StreamClient.INPUT2) + public String process(OrderDTO message) { + log.info("StreamReceiver: {}", message); + return "received."; + } + + @StreamListener(value = StreamClient.INPUT2) + public void process2(String message) { + log.info("StreamReceiver2: {}", message); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d201c636 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/repository/OrderDetailRepository.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.order.repository; + +import cn.lastwhisper.order.domain.OrderDetail; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +/** + * @author lastwhisper + */ +public interface OrderDetailRepository extends JpaRepository { + + List findByOrOrderId(String orderId); +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..f2a44f7f --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/repository/OrderMasterRepository.java @@ -0,0 +1,12 @@ +package cn.lastwhisper.order.repository; + +import cn.lastwhisper.order.domain.OrderMaster; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +public interface OrderMasterRepository extends JpaRepository { +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..bbf1dedb --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/service/OrderService.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.order.service; + +import cn.lastwhisper.order.dto.OrderDTO; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +public interface OrderService { + /** + * buyer创建订单 + */ + OrderDTO create(OrderDTO orderDTO); + /** + * seller结束订单 + */ + OrderDTO finish(String orderId); + +} 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/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..087ece2a --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/utils/JsonUtil.java @@ -0,0 +1,61 @@ +package cn.lastwhisper.order.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; + +/** + * Created by 廖师兄 + * 2018-02-21 10:40 + */ +public class JsonUtil { + + private static ObjectMapper objectMapper = new ObjectMapper(); + + /** + * 转换为json字符串 + * @param object + * @return + */ + public static String toJson(Object object) { + try { + return objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return null; + } + + /** + * json转对象 + * @param string + * @param classType + * @return + */ + public static Object fromJson(String string, Class classType) { + try { + return objectMapper.readValue(string, classType); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + + /** + * json转对象 + * @param string + * @param typeReference + * @return + */ + public static Object fromJson(String string, TypeReference typeReference) { + try { + return objectMapper.readValue(string, typeReference); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..7c4f34de --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/utils/KeyUtil.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.order.utils; + +import java.util.Random; + +/** + * Created by 廖师兄 + * 2017-12-10 16:57 + */ +public class KeyUtil { + + /** + * 生成唯一的主键 + * 格式: 时间+随机数 + */ + public static synchronized String genUniqueKey() { + Random random = new Random(); + Integer number = random.nextInt(900000) + 100000; + + return System.currentTimeMillis() + String.valueOf(number); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..752d345f --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/utils/ResultVOUtil.java @@ -0,0 +1,19 @@ +package cn.lastwhisper.order.utils; + + +import cn.lastwhisper.order.vo.ResultVO; + +/** + * Created by 廖师兄 + * 2017-12-10 18:03 + */ +public class ResultVOUtil { + + public static ResultVO success(Object object) { + ResultVO resultVO = new ResultVO(); + resultVO.setCode(0); + resultVO.setMsg("成功"); + resultVO.setData(object); + return resultVO; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..ae016453 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/vo/ResultVO.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.order.vo; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * http响应最外层数据 + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +@NoArgsConstructor +public class ResultVO { + /** + * 响应码 + */ + private Integer code; + /** + * 响应消息 + */ + private String msg; + /** + * 响应内容 + */ + private T data; +} 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/distributed/springcloud-netflix/order/order-server/src/main/resources/application.txt b/distributed/springcloud-netflix/order/order-server/src/main/resources/application.txt new file mode 100644 index 00000000..6dd3d2a5 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/resources/application.txt @@ -0,0 +1,16 @@ +spring: + application: + name: order + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/springcloud?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false + username: root + password: root + jpa: + show-sql: true +eureka: + client: + service-url: + defaultZone: http://localhost:8761/eureka/ +server: + port: 8081 \ No newline at end of file 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/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..b4fa5dce --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/MqSenderTest.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.order; + +import org.junit.Test; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Date; + +/** + * 发送MQ消息 + * @author lastwhisper + * @date 2019/10/31 + */ +public class MqSenderTest extends OrderApplicationTests { + + @Autowired + private AmqpTemplate amqpTemplate; + + @Test + public void testMqSend() { + amqpTemplate.convertAndSend("myQueue", "now :" + new Date()); + } + + @Test + public void testMqSendOrder() { + amqpTemplate.convertAndSend("myOrder", "computer","now :" + new Date()); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..a2b55963 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.order; + +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + + +@RunWith(SpringRunner.class) +@SpringBootTest +@TestPropertySource("classpath:bootstrap.yml") +public class OrderApplicationTests { + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..cbafedc6 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/repository/OrderDetailRepositoryTest.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.order.repository; + +import cn.lastwhisper.order.OrderApplicationTests; +import cn.lastwhisper.order.domain.OrderDetail; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.math.BigDecimal; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +public class OrderDetailRepositoryTest extends OrderApplicationTests { + + @Autowired + private OrderDetailRepository orderDetailRepository; + + @Test + public void testSave() { + OrderDetail orderDetail = new OrderDetail(); + orderDetail.setDetailId("12367"); + orderDetail.setOrderId("123456"); + orderDetail.setProductIcon("http://xxx.com"); + orderDetail.setProductId("157875196366160022"); + orderDetail.setProductName("皮蛋粥"); + orderDetail.setProductPrice(new BigDecimal(0.01)); + orderDetail.setProductQuantity(2); + + OrderDetail result = orderDetailRepository.save(orderDetail); + Assert.assertTrue(result != null); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..74c7e482 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/repository/OrderMasterRepositoryTest.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.order.repository; + + +import cn.lastwhisper.order.OrderApplicationTests; +import cn.lastwhisper.order.domain.OrderMaster; +import cn.lastwhisper.order.enums.OrderStatusEnum; +import cn.lastwhisper.order.enums.PayStatusEnum; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.math.BigDecimal; + +public class OrderMasterRepositoryTest extends OrderApplicationTests { + + @Autowired + private OrderMasterRepository orderMasterRepository; + + @Test + public void testSave() { + OrderMaster orderMaster = new OrderMaster(); + orderMaster.setOrderId("1234567"); + orderMaster.setBuyerName("师兄"); + orderMaster.setBuyerPhone("1886131241241"); + orderMaster.setBuyerAddress("慕课网总部"); + orderMaster.setBuyerOpenid("1101110"); + orderMaster.setOrderAmount(new BigDecimal(2.5)); + orderMaster.setOrderStatus(OrderStatusEnum.NEW.getCode()); + orderMaster.setPayStatus(PayStatusEnum.WAIT.getCode()); + + OrderMaster result = orderMasterRepository.save(orderMaster); + Assert.assertTrue(result != null); + } + +} \ No newline at end of file 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/distributed/springcloud-netflix/product-old/pom.xml b/distributed/springcloud-netflix/product-old/pom.xml new file mode 100644 index 00000000..9e3967bf --- /dev/null +++ b/distributed/springcloud-netflix/product-old/pom.xml @@ -0,0 +1,90 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + cn.lastwhisper + product-old + 0.0.1-SNAPSHOT + product-old + Demo project for Spring Boot + + + 1.8 + Finchley.RELEASE + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + mysql + mysql-connector-java + runtime + + + org.projectlombok + lombok + true + + + 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 + + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + + diff --git a/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/ProductApplication.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/ProductApplication.java new file mode 100644 index 00000000..8f9ebc5e --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/ProductApplication.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.product; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +@SpringBootApplication +@EnableDiscoveryClient +//@EntityScan(basePackages = "cn.lastwhisper.product.domain") +//@EnableJpaRepositories(basePackages = "cn.lastwhisper.product.repository") +public class ProductApplication { + + public static void main(String[] args) { + SpringApplication.run(ProductApplication.class, args); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..49bc04b7 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/controller/ProductController.java @@ -0,0 +1,92 @@ +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) { + return productService.findList(productIdList); + } + + @PostMapping("decreaseStock") + public void decreaseStock(@RequestBody List cartDTOList) { + productService.decreaseStock(cartDTOList); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d27db3d4 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/controller/ServerController.java @@ -0,0 +1,19 @@ +package cn.lastwhisper.product.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@RestController +public class ServerController { + + @GetMapping("/msg") + public String msg() { + return "this is product' msg"; + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..31746d25 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/domain/ProductCategory.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.product.domain; + +import lombok.*; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +@Entity +@Table(name = "product_category")//默认支持驼峰 +public class ProductCategory { + + @Id + @GeneratedValue + private Integer categoryId; + /** 类目名字 */ + private String categoryName; + /** 类目编号 */ + private Integer categoryType; + + private Date createTime; + + private Date updateTime; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..074a025f --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/domain/ProductInfo.java @@ -0,0 +1,52 @@ +package cn.lastwhisper.product.domain; + +import lombok.*; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.math.BigDecimal; +import java.util.Date; + +/** + * product_info表对应的实体类 + * @author lastwhisper + * @date 2019/10/24 + */ +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +@Entity +@Table(name = "product_info") +public class ProductInfo { + + @Id + private String productId; + + /** 名字. */ + private String productName; + + /** 单价. */ + private BigDecimal productPrice; + + /** 库存. */ + private Integer productStock; + + /** 描述. */ + private String productDescription; + + /** 小图. */ + private String productIcon; + + /** 状态, 0正常1下架. */ + private Integer productStatus; + + /** 类目编号. */ + private Integer categoryType; + + private Date createTime; + + private Date updateTime; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..5f840f09 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/dto/CartDTO.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.product.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class CartDTO { + + private String productId; + + private Integer productQuantity; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..2874ac7e --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/enums/ProductStatusEnum.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.product.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 商品上下架状态枚举 + * @author lastwhisper + * @date 2019/10/26 + */ +@AllArgsConstructor +@Getter +public enum ProductStatusEnum { + /*在架商品*/ + UP(0, "在架"), + /*下架商品*/ + DOWN(1, "下架"); + + private Integer code; + private String msg; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..8f823fd3 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/enums/ResultEnum.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.product.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@Getter +@AllArgsConstructor +public enum ResultEnum { + /*商品不存在*/ + PRODUCT_NOT_EXIST(1, "商品不存在"), + PRODUCT_STOCK_ERROR(2,"商品库存不足") + ; + + private Integer code; + private String msg; + + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..83b47d65 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/exception/ProductExecption.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.product.exception; + +import cn.lastwhisper.product.enums.ResultEnum; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +public class ProductExecption extends RuntimeException { + + private Integer code; + + public ProductExecption(Integer code, String message) { + super(message); + this.code = code; + } + + public ProductExecption(ResultEnum resultEnum) { + this(resultEnum.getCode(), resultEnum.getMsg()); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..a7aea936 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/repository/ProductCategoryRepository.java @@ -0,0 +1,16 @@ +package cn.lastwhisper.product.repository; + +import cn.lastwhisper.product.domain.ProductCategory; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/24 + */ +public interface ProductCategoryRepository extends JpaRepository { + + List findByCategoryTypeIn(List categoryTypeList); +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d65d2e4c --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/repository/ProductInfoRepository.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.product.repository; + +import cn.lastwhisper.product.domain.ProductInfo; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/24 + */ +public interface ProductInfoRepository extends JpaRepository { + + /** + * 根据商品状态获取商品列表 + * 状态, 0正常1下架. + * + */ + public List findByProductStatus(Integer productStatus); + + public List findByProductIdIn(List productIdList); +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..166c2c82 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/CategoryService.java @@ -0,0 +1,11 @@ +package cn.lastwhisper.product.service; + +import cn.lastwhisper.product.domain.ProductCategory; + +import java.util.List; + +public interface CategoryService { + + List findByCategoryTypeIn(List categoryTypeList); + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..46fc05ad --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/ProductService.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.product.service; + +import cn.lastwhisper.product.domain.ProductInfo; +import cn.lastwhisper.product.dto.CartDTO; + +import java.util.List; + +/** + * @author Administrator + */ +public interface ProductService { + + /** + * 查询所有在架商品 + */ + List findUpAll(); + + List findList(List productIdList); + + /** + * 扣库存 + * 1.先检查商品是否存在 + * 2.再检查库存是否充足 + * 3.有一项不通过抛异常回滚事务 + */ + void decreaseStock(List cartDTOList); +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..87c1249b --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/impl/CategoryServiceImpl.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.product.service.impl; + +import cn.lastwhisper.product.domain.ProductCategory; +import cn.lastwhisper.product.repository.ProductCategoryRepository; +import cn.lastwhisper.product.service.CategoryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 类目 + * @author lastwhisper + * @date 2019/10/26 + */ +@Service +public class CategoryServiceImpl implements CategoryService { + + @Autowired + private ProductCategoryRepository productCategoryRepository; + + @Override + public List findByCategoryTypeIn(List categoryTypeList) { + return productCategoryRepository.findByCategoryTypeIn(categoryTypeList); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d8bed968 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/impl/ProductServiceImpl.java @@ -0,0 +1,72 @@ +package cn.lastwhisper.product.service.impl; + +import cn.lastwhisper.product.domain.ProductInfo; +import cn.lastwhisper.product.dto.CartDTO; +import cn.lastwhisper.product.enums.ProductStatusEnum; +import cn.lastwhisper.product.enums.ResultEnum; +import cn.lastwhisper.product.exception.ProductExecption; +import cn.lastwhisper.product.repository.ProductInfoRepository; +import cn.lastwhisper.product.service.ProductService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.List; +import java.util.Optional; + +/** + * 商品业务 + * @author lastwhisper + * @date 2019/10/26 + */ +@Service +@Slf4j +public class ProductServiceImpl implements ProductService { + + @Autowired + private ProductInfoRepository productInfoRepository; + + @Override + public List findUpAll() { + // 不要直接使用硬编码 + return productInfoRepository.findByProductStatus(ProductStatusEnum.UP.getCode()); + } + + @Override + public List findList(List productIdList) { + return productInfoRepository.findByProductIdIn(productIdList); + } + + /** + * 扣库存 + * 1.先检查商品是否存在 + * 2.再检查库存是否充足 + * 3.有一项不通过抛异常回滚事务 + */ + @Override + @Transactional + public void decreaseStock(List cartDTOList) { + for (CartDTO cartDTO : cartDTOList) { + Optional optionalProductInfo = productInfoRepository.findById(cartDTO.getProductId()); + // 1.检查商品是否存在 + if (!optionalProductInfo.isPresent()) { + //log.error("[扣库存]商品不存在 cartDTO={}", cartDTO); + throw new ProductExecption(ResultEnum.PRODUCT_NOT_EXIST); + } + // 2.检查库存是否充足 + ProductInfo productInfo = optionalProductInfo.get(); + Integer surplusStock = productInfo.getProductStock() - cartDTO.getProductQuantity(); + if (surplusStock < 0) { + //log.error("[扣库存]商品剩余库存不足 cartDTO={}", cartDTO); + throw new ProductExecption(ResultEnum.PRODUCT_STOCK_ERROR); + } + + // 3.保存库存 + productInfo.setProductStock(surplusStock); + productInfoRepository.save(productInfo); + + } + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..080a5f5f --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/utils/ResultVOUtil.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.product.utils; + +import cn.lastwhisper.product.vo.ResultVO; + +/** + * http响应结果集工具类 + * @author lastwhisper + * @date 2019/10/26 + */ +public class ResultVOUtil { + + public static ResultVO success(Object object) { + ResultVO resultVO = new ResultVO(); + resultVO.setCode(0); + resultVO.setMsg("成功"); + resultVO.setData(object); + return resultVO; + } + + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..8c7aa306 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/vo/ProductInfoVO.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.product.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.math.BigDecimal; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +@NoArgsConstructor +public class ProductInfoVO { + + @JsonProperty("id") + private String productId; + + @JsonProperty("name") + private String productName; + + @JsonProperty("price") + private BigDecimal productPrice; + + @JsonProperty("description") + private String productDescription; + + @JsonProperty("icon") + private String productIcon; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..b1769b78 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/vo/ProductVO.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.product.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +@NoArgsConstructor +public class ProductVO { + + @JsonProperty("name") + private String categoryName; + + @JsonProperty("type") + private Integer categoryType; + + @JsonProperty("foods") + private List productInfoVOList; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..2fa0e276 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/vo/ResultVO.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.product.vo; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * http响应最外层数据 + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +@NoArgsConstructor +public class ResultVO { + /** + * 响应码 + */ + private Integer code; + /** + * 响应消息 + */ + private String msg; + /** + * 响应内容 + */ + private T data; +} diff --git a/distributed/springcloud-netflix/product-old/src/main/resources/application.yml b/distributed/springcloud-netflix/product-old/src/main/resources/application.yml new file mode 100644 index 00000000..e65f147b --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/main/resources/application.yml @@ -0,0 +1,15 @@ +spring: + application: + name: product + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/springcloud?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false + username: root + password: root + jpa: + show-sql: true +eureka: + client: + service-url: + defaultZone: http://localhost:8761/eureka/ + diff --git a/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/ProductApplicationTests.java b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/ProductApplicationTests.java new file mode 100644 index 00000000..9a9c4956 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/ProductApplicationTests.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.product; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +@TestPropertySource("classpath:application.yml") +public class ProductApplicationTests { + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..fec0f602 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/repository/ProductCategoryRepositoryTest.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.product.repository; + +import cn.lastwhisper.product.ProductApplicationTests; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Arrays; +public class ProductCategoryRepositoryTest extends ProductApplicationTests { + + @Autowired + private ProductCategoryRepository productCategoryRepository; + + @Test + public void findProductCategoryByCategoryTypeIn() { + productCategoryRepository.findByCategoryTypeIn(Arrays.asList(1, 22)).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..cd6fbe2a --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/repository/ProductInfoRepositoryTest.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.product.repository; + +import cn.lastwhisper.product.ProductApplicationTests; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Arrays; + +public class ProductInfoRepositoryTest extends ProductApplicationTests { + + @Autowired + private ProductInfoRepository productInfoRepository; + + @Test + public void findAllByProductStatus() { + productInfoRepository.findByProductStatus(0).forEach(System.out::println); + } + + @Test + public void findByProductIdIn() { + productInfoRepository.findByProductIdIn(Arrays.asList("157875196366160022")).forEach(System.out::println); + } + +} \ No newline at end of file diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..c9b46cdc --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/service/CategoryServiceTest.java @@ -0,0 +1,18 @@ +package cn.lastwhisper.product.service; + +import cn.lastwhisper.product.ProductApplicationTests; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Arrays; + +public class CategoryServiceTest extends ProductApplicationTests { + + @Autowired + private CategoryService categoryService; + + @Test + public void findByCategoryTypeIn() { + categoryService.findByCategoryTypeIn(Arrays.asList(1, 2)).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..3200ccf2 --- /dev/null +++ b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/service/ProductServiceTest.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.product.service; + +import cn.lastwhisper.product.ProductApplicationTests; +import cn.lastwhisper.product.dto.CartDTO; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Arrays; + +public class ProductServiceTest extends ProductApplicationTests { + + @Autowired + private ProductService productService; + + @Test + public void findUpAll() { + productService.findUpAll().forEach(System.out::println); + } + + @Test + public void decreaseStock(){ + CartDTO cartDTO = new CartDTO("157875227953464068", 3); + productService.decreaseStock(Arrays.asList(cartDTO)); + } +} \ No newline at end of file diff --git a/distributed/springcloud-netflix/product/pom.xml b/distributed/springcloud-netflix/product/pom.xml new file mode 100644 index 00000000..4f48b9a4 --- /dev/null +++ b/distributed/springcloud-netflix/product/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + + product-server + product-common + product-client + + + cn.lastwhisper + product + 0.0.1-SNAPSHOT + pom + + product + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + Finchley.RELEASE + 0.0.1-SNAPSHOT + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + cn.lastwhisper + product-common + ${product-common.version} + + + + + diff --git a/distributed/springcloud-netflix/product/product-client/pom.xml b/distributed/springcloud-netflix/product/product-client/pom.xml new file mode 100644 index 00000000..3a9acc7c --- /dev/null +++ b/distributed/springcloud-netflix/product/product-client/pom.xml @@ -0,0 +1,27 @@ + + + + product + cn.lastwhisper + 0.0.1-SNAPSHOT + + 4.0.0 + + product-client + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + cn.lastwhisper + product-common + + + + \ No newline at end of file diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..7c697fc8 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-client/src/main/java/cn/lastwhisper/product/client/ProductClient.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.product.client; + +import cn.lastwhisper.product.common.DecreaseStockInput; +import cn.lastwhisper.product.common.ProductInfoOutput; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@FeignClient("product") +public interface ProductClient { + + @GetMapping("/msg") + String productMsg(); + + @PostMapping("/product/listForOrder") + List listForOrder(@RequestBody List productIdList); + + @PostMapping("/product/decreaseStock") + void decreaseStock(@RequestBody List cartDTOList); + + /** + * 一个睡3s的方法 + */ + @PostMapping("/product/productThread3") + void productThread3(); + +} diff --git a/distributed/springcloud-netflix/product/product-common/pom.xml b/distributed/springcloud-netflix/product/product-common/pom.xml new file mode 100644 index 00000000..12b125f7 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-common/pom.xml @@ -0,0 +1,22 @@ + + + + product + cn.lastwhisper + 0.0.1-SNAPSHOT + + 4.0.0 + + product-common + + + + + org.projectlombok + lombok + + + + \ No newline at end of file diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..1ac2fbc0 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-common/src/main/java/cn/lastwhisper/product/common/DecreaseStockInput.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.product.common; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * 对应CartDTO + * @author lastwhisper + * @date 2019/10/30 + */ +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class DecreaseStockInput { + private String productId; + + private Integer productQuantity; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..04ae1888 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-common/src/main/java/cn/lastwhisper/product/common/ProductInfoOutput.java @@ -0,0 +1,43 @@ +package cn.lastwhisper.product.common; + +import lombok.Getter; +import lombok.Setter; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 对应ProductInfo + * @author lastwhisper + * @date 2019/10/30 + */ +@Getter +@Setter +public class ProductInfoOutput { + private String productId; + + /** 名字. */ + private String productName; + + /** 单价. */ + private BigDecimal productPrice; + + /** 库存. */ + private Integer productStock; + + /** 描述. */ + private String productDescription; + + /** 小图. */ + private String productIcon; + + /** 状态, 0正常1下架. */ + private Integer productStatus; + + /** 类目编号. */ + private Integer categoryType; + + private Date createTime; + + private Date updateTime; +} 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/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d27db3d4 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/controller/ServerController.java @@ -0,0 +1,19 @@ +package cn.lastwhisper.product.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@RestController +public class ServerController { + + @GetMapping("/msg") + public String msg() { + return "this is product' msg"; + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..31746d25 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/domain/ProductCategory.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.product.domain; + +import lombok.*; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +@Entity +@Table(name = "product_category")//默认支持驼峰 +public class ProductCategory { + + @Id + @GeneratedValue + private Integer categoryId; + /** 类目名字 */ + private String categoryName; + /** 类目编号 */ + private Integer categoryType; + + private Date createTime; + + private Date updateTime; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..eb0f3e83 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/domain/ProductInfo.java @@ -0,0 +1,53 @@ +package cn.lastwhisper.product.domain; + +import lombok.*; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.math.BigDecimal; +import java.util.Date; + +/** + * product_info表对应的实体类 + * @author lastwhisper + * @date 2019/10/24 + */ +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +@Entity +@Table(name = "product_info") +public class ProductInfo { + + @Id + private String productId; + + /** 名字. */ + private String productName; + + /** 单价. */ + private BigDecimal productPrice; + + /** 库存. */ + private Integer productStock; + + /** 描述. */ + private String productDescription; + + /** 小图. */ + private String productIcon; + + /** 状态, 0正常1下架. */ + private Integer productStatus; + + /** 类目编号. */ + private Integer categoryType; + + private Date createTime; + + private Date updateTime; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..5f840f09 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/dto/CartDTO.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.product.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class CartDTO { + + private String productId; + + private Integer productQuantity; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..2874ac7e --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/enums/ProductStatusEnum.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.product.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 商品上下架状态枚举 + * @author lastwhisper + * @date 2019/10/26 + */ +@AllArgsConstructor +@Getter +public enum ProductStatusEnum { + /*在架商品*/ + UP(0, "在架"), + /*下架商品*/ + DOWN(1, "下架"); + + private Integer code; + private String msg; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..8f823fd3 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/enums/ResultEnum.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.product.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@Getter +@AllArgsConstructor +public enum ResultEnum { + /*商品不存在*/ + PRODUCT_NOT_EXIST(1, "商品不存在"), + PRODUCT_STOCK_ERROR(2,"商品库存不足") + ; + + private Integer code; + private String msg; + + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..83b47d65 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/exception/ProductExecption.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.product.exception; + +import cn.lastwhisper.product.enums.ResultEnum; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +public class ProductExecption extends RuntimeException { + + private Integer code; + + public ProductExecption(Integer code, String message) { + super(message); + this.code = code; + } + + public ProductExecption(ResultEnum resultEnum) { + this(resultEnum.getCode(), resultEnum.getMsg()); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..a7aea936 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/repository/ProductCategoryRepository.java @@ -0,0 +1,16 @@ +package cn.lastwhisper.product.repository; + +import cn.lastwhisper.product.domain.ProductCategory; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/24 + */ +public interface ProductCategoryRepository extends JpaRepository { + + List findByCategoryTypeIn(List categoryTypeList); +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..d65d2e4c --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/repository/ProductInfoRepository.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.product.repository; + +import cn.lastwhisper.product.domain.ProductInfo; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/24 + */ +public interface ProductInfoRepository extends JpaRepository { + + /** + * 根据商品状态获取商品列表 + * 状态, 0正常1下架. + * + */ + public List findByProductStatus(Integer productStatus); + + public List findByProductIdIn(List productIdList); +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..166c2c82 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/CategoryService.java @@ -0,0 +1,11 @@ +package cn.lastwhisper.product.service; + +import cn.lastwhisper.product.domain.ProductCategory; + +import java.util.List; + +public interface CategoryService { + + List findByCategoryTypeIn(List categoryTypeList); + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..46fc05ad --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/ProductService.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.product.service; + +import cn.lastwhisper.product.domain.ProductInfo; +import cn.lastwhisper.product.dto.CartDTO; + +import java.util.List; + +/** + * @author Administrator + */ +public interface ProductService { + + /** + * 查询所有在架商品 + */ + List findUpAll(); + + List findList(List productIdList); + + /** + * 扣库存 + * 1.先检查商品是否存在 + * 2.再检查库存是否充足 + * 3.有一项不通过抛异常回滚事务 + */ + void decreaseStock(List cartDTOList); +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..87c1249b --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/impl/CategoryServiceImpl.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.product.service.impl; + +import cn.lastwhisper.product.domain.ProductCategory; +import cn.lastwhisper.product.repository.ProductCategoryRepository; +import cn.lastwhisper.product.service.CategoryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 类目 + * @author lastwhisper + * @date 2019/10/26 + */ +@Service +public class CategoryServiceImpl implements CategoryService { + + @Autowired + private ProductCategoryRepository productCategoryRepository; + + @Override + public List findByCategoryTypeIn(List categoryTypeList) { + return productCategoryRepository.findByCategoryTypeIn(categoryTypeList); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..eb51b2ea --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/impl/ProductServiceImpl.java @@ -0,0 +1,95 @@ +package cn.lastwhisper.product.service.impl; + +import cn.lastwhisper.product.common.ProductInfoOutput; +import cn.lastwhisper.product.domain.ProductInfo; +import cn.lastwhisper.product.dto.CartDTO; +import cn.lastwhisper.product.enums.ProductStatusEnum; +import cn.lastwhisper.product.enums.ResultEnum; +import cn.lastwhisper.product.exception.ProductExecption; +import cn.lastwhisper.product.repository.ProductInfoRepository; +import cn.lastwhisper.product.service.ProductService; +import cn.lastwhisper.product.utils.JsonUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * 商品业务 + * @author lastwhisper + * @date 2019/10/26 + */ +@Service +@Slf4j +public class ProductServiceImpl implements ProductService { + + @Autowired + private AmqpTemplate amqpTemplate; + + @Autowired + private ProductInfoRepository productInfoRepository; + + @Override + public List findUpAll() { + // 不要直接使用硬编码 + return productInfoRepository.findByProductStatus(ProductStatusEnum.UP.getCode()); + } + + @Override + public List findList(List productIdList) { + return productInfoRepository.findByProductIdIn(productIdList); + } + + /** + * 扣库存 + * 1.先检查商品是否存在 + * 2.再检查库存是否充足 + * 3.有一项不通过抛异常回滚事务 + */ + @Override + public void decreaseStock(List cartDTOList) { + List productInfoList = decreaseStockProcess(cartDTOList); + List productInfoOutputList = productInfoList.stream().map(p -> { + ProductInfoOutput productInfoOutput = new ProductInfoOutput(); + BeanUtils.copyProperties(p, productInfoOutput); + return productInfoOutput; + }).collect(Collectors.toList()); + + amqpTemplate.convertAndSend("productInfo", JsonUtil.toJson(productInfoOutputList)); + } + + @Transactional + public List decreaseStockProcess(List cartDTOList) { + List productInfoList = new ArrayList<>(); + for (CartDTO cartDTO : cartDTOList) { + Optional optionalProductInfo = productInfoRepository.findById(cartDTO.getProductId()); + // 1.检查商品是否存在 + if (!optionalProductInfo.isPresent()) { + // log.error("[扣库存]商品不存在 cartDTO={}", cartDTO); + throw new ProductExecption(ResultEnum.PRODUCT_NOT_EXIST); + } + // 2.检查库存是否充足 + ProductInfo productInfo = optionalProductInfo.get(); + Integer surplusStock = productInfo.getProductStock() - cartDTO.getProductQuantity(); + if (surplusStock < 0) { + // log.error("[扣库存]商品剩余库存不足 cartDTO={}", cartDTO); + throw new ProductExecption(ResultEnum.PRODUCT_STOCK_ERROR); + } + + // 3.保存库存 + productInfo.setProductStock(surplusStock); + productInfoRepository.save(productInfo); + + productInfoList.add(productInfo); + } + return productInfoList; + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..f9e240be --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/utils/JsonUtil.java @@ -0,0 +1,61 @@ +package cn.lastwhisper.product.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; + +/** + * Created by 廖师兄 + * 2018-02-21 10:40 + */ +public class JsonUtil { + + private static ObjectMapper objectMapper = new ObjectMapper(); + + /** + * 转换为json字符串 + * @param object + * @return + */ + public static String toJson(Object object) { + try { + return objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return null; + } + + /** + * json转对象 + * @param string + * @param classType + * @return + */ + public static Object fromJson(String string, Class classType) { + try { + return objectMapper.readValue(string, classType); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + + /** + * json转对象 + * @param string + * @param typeReference + * @return + */ + public static Object fromJson(String string, TypeReference typeReference) { + try { + return objectMapper.readValue(string, typeReference); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..25a2ef00 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/utils/ResultVOUtil.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.product.utils; + +import cn.lastwhisper.product.vo.ResultVO; + +/** + * http响应结果集工具类 + * @author lastwhisper + * @date 2019/10/26 + */ +public class ResultVOUtil { + + public static ResultVO success(Object object) { + ResultVO resultVO = new ResultVO(); + resultVO.setCode(0); + resultVO.setMsg("成功"); + resultVO.setData(object); + return resultVO; + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..8c7aa306 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/vo/ProductInfoVO.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.product.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.math.BigDecimal; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +@NoArgsConstructor +public class ProductInfoVO { + + @JsonProperty("id") + private String productId; + + @JsonProperty("name") + private String productName; + + @JsonProperty("price") + private BigDecimal productPrice; + + @JsonProperty("description") + private String productDescription; + + @JsonProperty("icon") + private String productIcon; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..b1769b78 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/vo/ProductVO.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.product.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +@NoArgsConstructor +public class ProductVO { + + @JsonProperty("name") + private String categoryName; + + @JsonProperty("type") + private Integer categoryType; + + @JsonProperty("foods") + private List productInfoVOList; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..2fa0e276 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/vo/ResultVO.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.product.vo; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * http响应最外层数据 + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +@NoArgsConstructor +public class ResultVO { + /** + * 响应码 + */ + private Integer code; + /** + * 响应消息 + */ + private String msg; + /** + * 响应内容 + */ + private T data; +} diff --git a/distributed/springcloud-netflix/product/product-server/src/main/resources/application.txt b/distributed/springcloud-netflix/product/product-server/src/main/resources/application.txt new file mode 100644 index 00000000..e65f147b --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/resources/application.txt @@ -0,0 +1,15 @@ +spring: + application: + name: product + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/springcloud?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false + username: root + password: root + jpa: + show-sql: true +eureka: + client: + service-url: + defaultZone: http://localhost:8761/eureka/ + 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/distributed/springcloud-netflix/user/pom.xml b/distributed/springcloud-netflix/user/pom.xml new file mode 100644 index 00000000..8fc4e3b3 --- /dev/null +++ b/distributed/springcloud-netflix/user/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + + user-server + + + cn.lastwhisper + user + pom + 1.0-SNAPSHOT + user + 用户服务 + + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + Finchley.RELEASE + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + \ No newline at end of file diff --git a/distributed/springcloud-netflix/user/user-server/pom.xml b/distributed/springcloud-netflix/user/user-server/pom.xml new file mode 100644 index 00000000..0cfbcf95 --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/pom.xml @@ -0,0 +1,78 @@ + + + + user + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + user-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.boot + spring-boot-starter-data-redis + + + + mysql + mysql-connector-java + runtime + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..1f7a144f --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/UserApplication.java @@ -0,0 +1,15 @@ +package cn.lastwhisper.user; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +@SpringBootApplication +@EnableDiscoveryClient +public class UserApplication { + + public static void main(String[] args) { + SpringApplication.run(UserApplication.class, args); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..fdf1edf7 --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/constant/CookieConstant.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.user.constant; + +/** + * Created by 廖师兄 + * 2018-03-04 23:28 + */ +public interface CookieConstant { + + String TOKEN = "token"; + + String OPENID = "openid"; + + /** + * 过期时间(单位:s) + */ + Integer expire = 7200; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..8ea9899c --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/constant/RedisConstant.java @@ -0,0 +1,11 @@ +package cn.lastwhisper.user.constant; + +/** + * Created by 廖师兄 + * 2018-03-04 23:37 + */ +public interface RedisConstant { + + String TOKEN_TEMPLATE = "token_%s"; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..041d8baf --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/controller/LoginController.java @@ -0,0 +1,90 @@ +package cn.lastwhisper.user.controller; + +import cn.lastwhisper.user.constant.CookieConstant; +import cn.lastwhisper.user.constant.RedisConstant; +import cn.lastwhisper.user.domain.UserInfo; +import cn.lastwhisper.user.enums.ResultEnum; +import cn.lastwhisper.user.enums.RoleEnum; +import cn.lastwhisper.user.service.UserService; +import cn.lastwhisper.user.utils.CookieUtil; +import cn.lastwhisper.user.utils.ResultVOUtil; +import cn.lastwhisper.user.vo.ResultVO; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * + * @author lastwhisper + * @date 2019/11/3 + */ +@RestController +@RequestMapping("/login") +public class LoginController { + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Autowired + private UserService userService; + + @GetMapping("/buyer") + public ResultVO buyer(String openid, HttpServletResponse response) { + //1.根据openid查询数据库 + UserInfo userInfo = userService.findByOpenid(openid); + if (userInfo == null) { + return ResultVOUtil.error(ResultEnum.LOGIN_FAIL); + } + //2.判断角色 + if (!RoleEnum.BUYER.getCode().equals(userInfo.getRole())) { + return ResultVOUtil.error(ResultEnum.ROLE_ERROR); + } + //3.cookie里设置openid + CookieUtil.set(response, CookieConstant.OPENID, openid, CookieConstant.expire); + return ResultVOUtil.success(); + } + + @GetMapping("/seller") + public ResultVO seller(String openid, + HttpServletRequest request, + HttpServletResponse response) { + //判断是否已登录 + Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN); + if (cookie != null && + !StringUtils.isEmpty(stringRedisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_TEMPLATE, cookie.getValue())))) { + return ResultVOUtil.success(); + } + + //1.根据openid查询数据库 + UserInfo userInfo = userService.findByOpenid(openid); + if (userInfo == null) { + return ResultVOUtil.error(ResultEnum.LOGIN_FAIL); + } + //2.判断角色 + if (!RoleEnum.SELLER.getCode().equals(userInfo.getRole())) { + return ResultVOUtil.error(ResultEnum.ROLE_ERROR); + } + String token = UUID.randomUUID().toString(); + Integer expire = CookieConstant.expire; + + //3. redis设置key=UUID, value=openid + stringRedisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_TEMPLATE, token), + openid, + expire, + TimeUnit.SECONDS); + + //4.cookie里设置token=UUID + CookieUtil.set(response, CookieConstant.TOKEN, token, CookieConstant.expire); + return ResultVOUtil.success(); + } + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..3d2c79ac --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/domain/UserInfo.java @@ -0,0 +1,37 @@ +package cn.lastwhisper.user.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import java.util.Date; + +/** + * + * @author lastwhisper + * @date 2019/11/3 + */ +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class UserInfo { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private String id; + private String username; + private String password; + private String openid; + private Integer role; + private Date create_time; + private Date update_time; + + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..6b470bdd --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/enums/ResultEnum.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.user.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 返回错误结果枚举 + * @author lastwhisper + * @date 2019/10/28 + */ +@AllArgsConstructor +@Getter +public enum ResultEnum { + /*参数错误枚举*/ + LOGIN_FAIL(1,"登录失败"), + ROLE_ERROR(2,"角色错误") + ; + + private Integer code; + private String msg; + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..de264890 --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/enums/RoleEnum.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.user.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * + * @author lastwhisper + * @date 2019/11/3 + */ +@AllArgsConstructor +@Getter +public enum RoleEnum { + BUYER(1, "买家"), + SELLER(2, "卖家"), + ; + + private Integer code; + private String msg; +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..e82dc5dd --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/repository/UserRepository.java @@ -0,0 +1,15 @@ +package cn.lastwhisper.user.repository; + +import cn.lastwhisper.user.domain.UserInfo; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * + * @author lastwhisper + * @date 2019/11/3 + */ +public interface UserRepository extends JpaRepository { + + UserInfo findByOpenid(String openid); + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..2faf684d --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/service/UserService.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.user.service; + +import cn.lastwhisper.user.domain.UserInfo; + +/** + * + * @author lastwhisper + * @date 2019/11/3 + */ +public interface UserService { + + UserInfo findByOpenid(String openid); + +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..4a5212b5 --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/service/impl/UserServiceImpl.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.user.service.impl; + +import cn.lastwhisper.user.domain.UserInfo; +import cn.lastwhisper.user.repository.UserRepository; +import cn.lastwhisper.user.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * @author lastwhisper + * @date 2019/11/3 + */ +@Service +public class UserServiceImpl implements UserService { + @Autowired + private UserRepository userRepository; + + @Override + public UserInfo findByOpenid(String openid) { + return userRepository.findByOpenid(openid); + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..71d63ee7 --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/utils/CookieUtil.java @@ -0,0 +1,42 @@ +package cn.lastwhisper.user.utils; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Created by 廖师兄 + * 2018-03-04 23:25 + */ +public class CookieUtil { + + /** + * 设置cookie + * @param response + * @param name + * @param value + * @param maxAge + */ + public static void set(HttpServletResponse response, + String name, + String value, + int maxAge) { + Cookie cookie = new Cookie(name, value); + cookie.setPath("/"); + cookie.setMaxAge(maxAge); + response.addCookie(cookie); + } + + public static Cookie get(HttpServletRequest request, + String name) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie: cookies) { + if (name.equals(cookie.getName())) { + return cookie; + } + } + } + return null; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..f96453c9 --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/utils/JsonUtil.java @@ -0,0 +1,61 @@ +package cn.lastwhisper.user.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; + +/** + * Created by 廖师兄 + * 2018-02-21 10:40 + */ +public class JsonUtil { + + private static ObjectMapper objectMapper = new ObjectMapper(); + + /** + * 转换为json字符串 + * @param object + * @return + */ + public static String toJson(Object object) { + try { + return objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return null; + } + + /** + * json转对象 + * @param string + * @param classType + * @return + */ + public static Object fromJson(String string, Class classType) { + try { + return objectMapper.readValue(string, classType); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + + /** + * json转对象 + * @param string + * @param typeReference + * @return + */ + public static Object fromJson(String string, TypeReference typeReference) { + try { + return objectMapper.readValue(string, typeReference); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..bee24033 --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/utils/ResultVOUtil.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.user.utils; + + +import cn.lastwhisper.user.enums.ResultEnum; +import cn.lastwhisper.user.vo.ResultVO; + +/** + * Created by 廖师兄 + * 2017-12-10 18:03 + */ +public class ResultVOUtil { + + public static ResultVO success() { + ResultVO resultVO = new ResultVO(); + resultVO.setCode(0); + resultVO.setMsg("成功"); + return resultVO; + } + + public static ResultVO success(Object object) { + ResultVO resultVO = new ResultVO(); + resultVO.setCode(0); + resultVO.setMsg("成功"); + resultVO.setData(object); + return resultVO; + } + + public static ResultVO error(ResultEnum resultEnum) { + ResultVO resultVO = new ResultVO(); + resultVO.setCode(resultEnum.getCode()); + resultVO.setMsg("错误"); + resultVO.setData(resultEnum.getMsg()); + return resultVO; + } +} diff --git a/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..3e5531c1 --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/vo/ResultVO.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.user.vo; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * http响应最外层数据 + * @author lastwhisper + * @date 2019/10/26 + */ +@Getter +@Setter +@NoArgsConstructor +public class ResultVO { + /** + * 响应码 + */ + private Integer code; + /** + * 响应消息 + */ + private String msg; + /** + * 响应内容 + */ + private T data; +} diff --git a/distributed/springcloud-netflix/user/user-server/src/main/resources/bootstrap.yml b/distributed/springcloud-netflix/user/user-server/src/main/resources/bootstrap.yml new file mode 100644 index 00000000..e7037f40 --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/main/resources/bootstrap.yml @@ -0,0 +1,13 @@ +spring: + application: + name: user + 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/distributed/springcloud-netflix/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 new file mode 100644 index 00000000..7c898cee --- /dev/null +++ b/distributed/springcloud-netflix/user/user-server/src/test/java/cn/lastwhisper/test/UserApplicationTests.java @@ -0,0 +1,19 @@ +package cn.lastwhisper.test; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +//@RunWith(SpringRunner.class) +//@SpringBootTest +////@TestPropertySource("classpath:bootstrap.yml") +//public class UserApplicationTests { +// +// @Test +// public void loadContext() { +// +// } +// +//} 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/framework/flyway/src/main/resources/db/migration/V1__Create_person_table.sql b/framework/flyway/src/main/resources/db/migration/V1__Create_person_table.sql new file mode 100644 index 00000000..69dd049e --- /dev/null +++ b/framework/flyway/src/main/resources/db/migration/V1__Create_person_table.sql @@ -0,0 +1,4 @@ +create table PERSON ( + ID int not null, + NAME varchar(100) not null +); \ No newline at end of file diff --git a/framework/flyway/src/main/resources/db/migration/V2__Add_people.sql b/framework/flyway/src/main/resources/db/migration/V2__Add_people.sql new file mode 100644 index 00000000..0d8ed6fc --- /dev/null +++ b/framework/flyway/src/main/resources/db/migration/V2__Add_people.sql @@ -0,0 +1,3 @@ +insert into PERSON (ID, NAME) values (1, 'Axel'); +insert into PERSON (ID, NAME) values (2, 'Mr. Foo'); +insert into PERSON (ID, NAME) values (3, 'Ms. Bar'); \ No newline at end of file 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/framework/tika/src/main/resources/application.properties b/framework/tika/src/main/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/framework/tika/src/main/resources/application.properties @@ -0,0 +1 @@ + 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/framework/tika/src/test/resources/application.properties b/framework/tika/src/test/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/framework/tika/src/test/resources/application.properties @@ -0,0 +1 @@ + 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%2Fround-lake.dustinice.workers.dev%3A443%2Fhttps%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttps%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%2Fup.enterdesk.com%2Fedpic_source%2Fc3%2F28%2F51%2Fc328516d6a64807408f0180f8e7e9032.jpg%26refer%3Dhttps%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%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/basic/src/main/java/cn/cunchang/cpu/ControlCpu.java b/java-basic/basic/src/main/java/cn/cunchang/cpu/ControlCpu.java new file mode 100644 index 00000000..9af7cbba --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/cpu/ControlCpu.java @@ -0,0 +1,27 @@ +package cn.cunchang.cpu; + +/** + * 控制cpu利用率 + * @author lastwhisper + * @date 2019/11/23 + */ +public class ControlCpu { + + /** + * 利用率70% + */ + public static void main(String[] args) throws InterruptedException { + long busyTime = 7; + long nowSys; + int i = 0; + while (true) { + nowSys = System.currentTimeMillis(); + while ((System.currentTimeMillis() - nowSys) <= busyTime) { + i++; + System.out.println(i + " 测试输出"); + } + Thread.sleep(3); + } + } + +} 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 new file mode 100644 index 00000000..fc832c9f --- /dev/null +++ b/java-basic/concurrent/pom.xml @@ -0,0 +1,47 @@ + + + + 4.0.0 + + cn.lastwhisper + concurrent + pom + 1.0-SNAPSHOT + + jmm-specification + + + + + 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 new file mode 100644 index 00000000..a8c89314 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/DeadLockDemo.java @@ -0,0 +1,47 @@ +package cn.lastwhisper.concurrent.basic; + +import java.util.concurrent.TimeUnit; + +/** + * 死锁是指两个或者以上的进程在执行过程中, + * 因争夺资源而造成的一种相互等待的现象, + * 若无外力干涉那他们都将无法推进下去 + * jps -l + * jstack jid + * @author lastwhisper + */ +public class DeadLockDemo { + public static void main(String[] args) { + String lockA = "lockA"; + String lockB = "lockB"; + new Thread(new HoldLock(lockA, lockB)).start(); + new Thread(new HoldLock(lockB, lockA)).start(); + } +} + +class HoldLock implements Runnable { + + private final String lockA; + private final String lockB; + + public HoldLock(String lockA, String lockB) { + this.lockA = lockA; + this.lockB = lockB; + } + + @Override + public void run() { + synchronized (lockA) { + System.out.println(Thread.currentThread().getName() + "\t 获取lockA"); + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + synchronized (lockB) { + System.out.println(Thread.currentThread().getName() + "\t 获取lockB"); + } + } + } + +} 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/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/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/basic/createthread/TestCallable.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/createthread/TestCallable.java new file mode 100644 index 00000000..2ffa2e07 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/createthread/TestCallable.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.concurrent.basic.createthread; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + +/** + * 线程实现的第三种方式实现Callable + * @author lastwhisper + */ +public class TestCallable { + public static void main(String[] args) { + MyCallable callable = new MyCallable(); + //执行 Callable 方式,需要 FutureTask 实现类支持 + FutureTask futureTask = new FutureTask(callable); + new Thread(futureTask).start(); + try { + System.out.println("主线程阻塞等待"); + Integer result = futureTask.get();// FutureTask可以用于闭锁 + System.out.println(result); + System.out.println("主线程拿到返回值"); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + + } +} + +class MyCallable implements Callable { + + @Override + public Integer call() throws Exception { + int sum = 0; + for (int i = 0; i <= 100; i++) { + sum += i; + } + return sum; + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..6db17541 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalDemo.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.concurrent.basic.threadlocal; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * ThreadLocal解决线程不安全问题 + * @author lastwhisper + */ +public class ThreadLocalDemo { + private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + static ThreadLocal tl = new ThreadLocal<>(); + public static class ParseDate implements Runnable{ + private int i=0; + public ParseDate(int i) { + this.i = i; + } + + @Override + public void run() { + try { + 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) { + e.printStackTrace(); + } + } + } + + public static void main(String[] args){ + ExecutorService pool = Executors.newFixedThreadPool(10); + 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/ThreadLocalMemoryLeak.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalMemoryLeak.java new file mode 100644 index 00000000..43617de4 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalMemoryLeak.java @@ -0,0 +1,52 @@ +package cn.lastwhisper.concurrent.basic.threadlocal; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * ThreadLocal导致内存泄漏 + * 弱引用只是解决了key的内存问题 + * @author lastwhisper + */ +public class ThreadLocalMemoryLeak { + private final static int TASK_LOOP_SIZE = 100; + /*线程池*/ + final static ThreadPoolExecutor poolExecutor = new + ThreadPoolExecutor(5,5,1, TimeUnit.SECONDS,new LinkedBlockingQueue<>()); + + static class LocalVariable{ + private byte[] a = new byte[1024*1024*5];//5MB + } + + ThreadLocal localVariableThreadLocal; + + public static void main(String[] args){ + + for (int i = 0; i < TASK_LOOP_SIZE; i++) { + poolExecutor.execute(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(500); + // 第一次,仅使用局部变量 20MB + //LocalVariable localVariable = new LocalVariable(); + // 第二次 放入ThreadLocal 350MB + // ThreadLocal弱引用导致内存泄漏 + ThreadLocalMemoryLeak oom = new ThreadLocalMemoryLeak(); + oom.localVariableThreadLocal = new ThreadLocal<>(); + oom.localVariableThreadLocal.set(new LocalVariable()); + // 第三次 remove解决内存泄漏 20MB + oom.localVariableThreadLocal.remove(); + + System.out.println("use local variable"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }); + } + + } + +} 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 new file mode 100644 index 00000000..02639424 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocal_GC_Demo.java @@ -0,0 +1,74 @@ +package cn.lastwhisper.concurrent.basic.threadlocal; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * ThreadLocal + * @author lastwhisper + */ +public class ThreadLocal_GC_Demo { + static volatile CountDownLatch latch = new CountDownLatch(1000); + + static ThreadLocal tl = new ThreadLocal() { + @Override + protected void finalize() throws Throwable { + System.out.println(this.toString() + " is GC"); + } + }; + + public static class ParseDate implements Runnable { + private int i = 0; + + public ParseDate(int i) { + this.i = i; + } + + @Override + public void run() { + try { + if (tl.get() == null) { + tl.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") { + @Override + protected void finalize() throws Throwable { + System.out.println(this.toString() + " is GC"); + } + }); + 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 { + latch.countDown(); + } + } + } + + public static void main(String[] args) throws InterruptedException { + ExecutorService pool = Executors.newFixedThreadPool(10); + for (int i = 0; i < 1000; i++) { + pool.execute(new ParseDate(i)); + } + + latch.await(); + System.out.println("mission complete"); + tl = null; + System.gc(); + System.out.println("first GC complete"); + // 设置tl时,清除ThreadLocalMap中无效对象 + tl = new ThreadLocal<>(); + latch = new CountDownLatch(1000); + for (int i = 0; i < 1000; i++) { + pool.execute(new ParseDate(i)); + } + latch.await(); + Thread.sleep(500); + System.gc(); + System.out.println("second GC complete"); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/Main.java new file mode 100644 index 00000000..defaff3a --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/Main.java @@ -0,0 +1,52 @@ +package cn.lastwhisper.concurrent.basic.volatileDemo; + +public class Main { + + public static void main(String[] args) { + TestVolatile thread = new TestVolatile(); + thread.start(); + + while (true) { + int a = thread.getA(); + //int a = 5; + //int b = thread.getB(); + if (thread.isFlag() == 2) { + System.out.println("flag被改了"); + break; + } + } + } + +} + +class TestVolatile extends Thread{ + + int b = 0; + + volatile int a = 0; + + int[] n = new int[10]; + + @Override + public void run() { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + n[0] = 2; + System.out.println("flag:"+isFlag()); + } + + public int isFlag() { + return n[0]; + } + + public int getA(){ + return a; + } + + public int getB(){ + return b; + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..1fcd5094 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileDemo.java @@ -0,0 +1,41 @@ +package cn.lastwhisper.concurrent.basic.volatileDemo; + +/** + * @author lastwhisper + */ +public class VolatileDemo implements Runnable { + + /** + * 无volatile程序不会结束,主线程无法感知update线程修改的值 + * + */ + private volatile boolean[] flag = {false}; + + @Override + public void run() { + try { + Thread.sleep(200); + } catch (InterruptedException e) { + e.printStackTrace(); + } + flag[0] = true; + System.out.println("flag=" + flag[0]); + } + + public boolean isFlag() { + return flag[0]; + } + + public static void main(String[] args) throws InterruptedException { + VolatileDemo runnable = new VolatileDemo(); + new Thread(runnable,"update thread").start(); + while (true) { + if (runnable.isFlag()) { + System.out.println("-----------------"); + break; + } + //Thread.sleep(10); + } + } +} + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileDemo2.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileDemo2.java new file mode 100644 index 00000000..79026732 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileDemo2.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.concurrent.basic.volatileDemo; + +/** + * @author lastwhisper + */ +public class VolatileDemo2 { + static int[] arr = new int[]{1, 2}; + + public static void main(String[] args) { + new Thread(() -> { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + arr[1] = 1; + }).start(); + new Thread(() -> { + while (true) { + if (arr[1] == 1) { + System.out.println("arr[1]==1"); + break; + } + } + + }).start(); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileRefExample.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileRefExample.java new file mode 100644 index 00000000..fe4d9eb9 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileRefExample.java @@ -0,0 +1,65 @@ +package cn.lastwhisper.concurrent.basic.volatileDemo; + +import java.util.concurrent.TimeUnit; + +public class VolatileRefExample { + private static volatile Data data = new Data(-1, -1); + + private static class Data { + private int a; + private int b; + + public Data(int a, int b) { + this.a = a; + this.b = b; + } + + public void setA(int a) { + this.a = a; + } + + public void setB(int b) { + this.b = b; + } + + public int getA() { + return a; + } + + public int getB() { + return b; + } + } + + public static void main(String[] args) throws InterruptedException { + + for (int i = 0; i < 3; i++) { + int a = i; + int b = i; + //writer + Thread writerThread = new Thread(() -> { + data.setA(a); + try { + TimeUnit.MICROSECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + data.setB(b); + }); + //reader + Thread readerThread = new Thread(() -> { + int x = data.getA(); + int y = data.getB(); + if (x != y) { + System.out.printf("a = %s, b = %s%n", x, y); + } + }); + + writerThread.start(); + readerThread.start(); + writerThread.join(); + readerThread.join(); + } + System.out.println("finished"); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileRefExample2.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileRefExample2.java new file mode 100644 index 00000000..7600f067 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileRefExample2.java @@ -0,0 +1,56 @@ +package cn.lastwhisper.concurrent.basic.volatileDemo; + +import java.util.concurrent.TimeUnit; + +public class VolatileRefExample2 { + private static Data data = new Data(-1, -1); + + private static class Data { + private int a; + private int b; + + public Data(int a, int b) { + this.a = a; + this.b = b; + } + + public synchronized void setValues(int a, int b) { + this.a = a; + try { + TimeUnit.MICROSECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + this.b = b; + } + + public synchronized int[] getValues() { + return new int[]{a, b}; + } + } + + public static void main(String[] args) throws InterruptedException { + for (int i = 0; i < 30; i++) { + int a = i; + int b = i; + + //writer + Thread writerThread = new Thread(() -> {data.setValues(a, b);}); + + //reader + Thread readerThread = new Thread(() -> { + int[] values = data.getValues(); + int x = values[0]; + int y = values[1]; + if (x != y) { + System.out.printf("a = %s, b = %s%n", x, y); + } + }); + writerThread.start(); + readerThread.start(); + writerThread.join(); + readerThread.join(); + } + System.out.println("finished"); + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..23555e51 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/alternate/TestABCAlternateForLock.java @@ -0,0 +1,110 @@ +package cn.lastwhisper.concurrent.example.alternate; + +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 + * A、 B、 C,每个线程将自己的 ID 在屏幕上打印 10 遍,要 + * 求输出的结果必须按顺序显示。 + * 如: ABCABCABC…… 依次递归 + * 使用Lock+Condition的await+signal + * https://blog.csdn.net/xiaokang123456kao/article/details/77331878 + * @author lastwhisper + */ +public class TestABCAlternateForLock { + public static void main(String[] args) { + ABCAlternateDemo ad = new ABCAlternateDemo(); + + new Thread(() -> { + for (int i = 1; i <= 10; i++) { + ad.loopA(i); + } + }, "A").start(); + + new Thread(() -> { + for (int i = 1; i <= 10; i++) { + ad.loopB(i); + } + }, "B").start(); + + new Thread(() -> { + for (int i = 1; i <= 10; i++) { + ad.loopC(i); + + System.out.println("-----------------------------------"); + } + }, "C").start(); + } +} + +class ABCAlternateDemo { + private int nowThread = 1; + private Lock lock = new ReentrantLock(); + //用于控制三个线程 + private Condition condition1 = lock.newCondition(); + private Condition condition2 = lock.newCondition(); + private Condition condition3 = lock.newCondition(); + + public void loopA(int nowLoop) { + lock.lock(); + try { + //判断 当前线程是阻塞还是执行 + if (nowThread != 1) { + condition1.await(); + } + for (int i = 1; i <= 1; i++) { + System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + nowLoop); + } + //唤醒下一个线程 + nowThread = 2; + condition2.signal(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + + public void loopB(int nowLoop) { + lock.lock(); + try { + //判断 当前线程是阻塞还是执行 + if (nowThread != 2) { + condition2.await(); + } + for (int i = 1; i <= 1; i++) { + System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + nowLoop); + } + //唤醒下一个线程 + nowThread = 3; + condition3.signal(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + + public void loopC(int nowLoop) { + lock.lock(); + try { + //判断 当前线程是阻塞还是打印 + if (nowThread != 3) { + condition3.await(); + } + for (int i = 1; i <= 1; i++) { + System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + nowLoop); + } + //唤醒下一个线程 + nowThread = 1; + condition1.signal(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + +} 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/blockqueue/ProdConsumer_BlockQueueDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/blockqueue/ProdConsumer_BlockQueueDemo.java new file mode 100644 index 00000000..cb630ee6 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/blockqueue/ProdConsumer_BlockQueueDemo.java @@ -0,0 +1,89 @@ +package cn.lastwhisper.concurrent.example.productconsumer.blockqueue; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 使用阻塞队列 + * volatile/CAS/atomicInteger/BlockQueue/线程交互/原子引用 + * @author lastwhisper + */ +public class ProdConsumer_BlockQueueDemo { + public static void main(String[] args) { + Resource resource = new Resource(new ArrayBlockingQueue<>(10)); + new Thread(() -> { + System.out.println("生产线程启动"); + try { + resource.product(); + } catch (Exception e) { + e.printStackTrace(); + } + }, "product").start(); + + new Thread(() -> { + System.out.println("消费线程启动"); + try { + resource.consumer(); + } catch (Exception e) { + e.printStackTrace(); + } + + }, "consumer").start(); + //休眠五秒 + try { + TimeUnit.SECONDS.sleep(5); + } catch (InterruptedException e) { + e.printStackTrace(); + } + resource.stop(); + } +} + +class Resource { + + private volatile boolean FLAG = true; + private AtomicInteger atomicInteger = new AtomicInteger(); + private BlockingQueue blockingQueue; + + public Resource(BlockingQueue blockingQueue) { + this.blockingQueue = blockingQueue; + System.out.println(blockingQueue.getClass().getName()); + } + + public void product() throws InterruptedException { + Integer data; + boolean result; + while (FLAG) { + data = atomicInteger.incrementAndGet(); + result = blockingQueue.offer(data, 2L, TimeUnit.SECONDS); + if (result) { + System.out.println(Thread.currentThread().getName() + "\t 插入队列data:" + data + "成功"); + } else { + System.out.println(Thread.currentThread().getName() + "\t 插入队列data:" + data + "失败"); + } + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public void consumer() throws InterruptedException { + Integer val; + while (FLAG) { + val = blockingQueue.poll(2L, TimeUnit.SECONDS); + if (val == null) { + System.out.println(Thread.currentThread().getName() + "\t 超过两秒没收到消息"); + return; + } + System.out.println(Thread.currentThread().getName() + "\t 消费队列value:" + val + "成功"); + } + } + + public void stop() { + this.FLAG = false; + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/lockcondition/TestProductAndConsumerForLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/lockcondition/TestProductAndConsumerForLock.java new file mode 100644 index 00000000..93d97fdf --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/lockcondition/TestProductAndConsumerForLock.java @@ -0,0 +1,111 @@ +package cn.lastwhisper.concurrent.example.productconsumer.lockcondition; + +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 生产者消费者案例(等待唤醒机制),使用Lock+Condition; + * 1、线程( new Thread)、操作(get、sale)、资源类(店员) + * 2、判断、干货、通知 + * 3、防止虚假唤醒 + * @author lastwhisper + */ +public class TestProductAndConsumerForLock { + public static void main(String[] args) { + Clerk clerk = new Clerk(); + + new Thread(new Product(clerk), "生产者A").start(); + new Thread(new Consumer(clerk), "消费者B").start(); + new Thread(new Product(clerk), "生产者C").start(); + new Thread(new Consumer(clerk), "消费者D").start(); + } +} + +//店员 +class Clerk { + private Lock lock = new ReentrantLock(); + private Condition condition = lock.newCondition(); + private int product = 0; + + //进货(生产者线程调用) + public void get() { + lock.lock(); + try { + while (product >= 1) { + System.out.println("货物已满!"); + //货物满了之后生产者等待 + //this.wait(); + condition.await(); + } + System.out.println(Thread.currentThread().getName() + " : " + ++product); + //生产货物之后唤醒消费者 + //this.notifyAll(); + condition.signalAll(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + + //销售(消费者线程调用) + public void sale() { + lock.lock(); + try { + while (product <= 0) { + System.out.println("货物为空!"); + //货物为空之后消费者等待 + //this.wait(); + condition.await(); + } + System.out.println(Thread.currentThread().getName() + " : " + --product); + //消费货物之后唤醒生产者 + //this.notifyAll(); + condition.signalAll(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + + } +} + + +//生产者 +class Product implements Runnable { + private Clerk clerk; + + public Product(Clerk clerk) { + this.clerk = clerk; + } + + @Override + public void run() { + for (int i = 0; i < 20; i++) { + try { + Thread.sleep(200);//网络延迟 + } catch (InterruptedException e) { + e.printStackTrace(); + } + clerk.get(); + } + } +} + +//消费者 +class Consumer implements Runnable { + private Clerk clerk; + + public Consumer(Clerk clerk) { + this.clerk = clerk; + } + + @Override + public void run() { + for (int i = 0; i < 20; i++) { + clerk.sale(); + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer.java new file mode 100644 index 00000000..ce518640 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer.java @@ -0,0 +1,99 @@ +package cn.lastwhisper.concurrent.example.productconsumer.waitnotify; + +/** + * 生产者消费者案例(等待唤醒机制),使用synchronize+Object的wait和notify; + * 1.有问题版本1:等待了唤醒不了 + * 1.1前置知识:sleep放弃CPU执行权,不释放锁;wait释放CPU执行权,释放锁 + * 1.2问题产生原因: + * 此时状态:product=0;消费者线程剩余循环次数=1;生产者线程剩余循环次数=2 + * (1).消费者线程拿到锁执行sale()到this.wait(); + * (2).生产者线程拿到锁执行get(),此时product=1;生产者线程剩余循环次数=1 + * 同时 this.notifyAll()唤醒消费者线程; + * (3).消费者线程接着this.wait()之后执行,此时product=1;消费者线程剩余循环次数=0;---消费者线程不会再执行 + * (4).生产者线程拿到锁执行get(),此时product=1,执行this.wait();---没有线程唤醒生产者线程 + * @author lastwhisper + */ +public class TestProductAndConsumer { + public static void main(String[] args) { + Clerk clerk = new Clerk(); + + new Thread(new Product(clerk), "生产者A").start(); + new Thread(new Consumer(clerk), "消费者B").start(); + } +} + +//店员 +class Clerk { + private int product = 0; + + //进货(生产者线程调用) + public synchronized void stock() {//循环次数:2——》1 + if (product >= 1) { +// System.out.println("货物已满!"); + try { + //货物满了之后生产者等待 + this.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } else { + System.out.println(Thread.currentThread().getName() + "添加商品,剩余数量" + ++product); + //生产货物之后唤醒消费者 + this.notifyAll(); + } + } + + //销售(消费者线程调用) + public synchronized void sale() {//product:0——》1,循环次数:1——》0 + if (product <= 0) { +// System.out.println("货物为空!"); + try { + //货物为空之后消费者等待 + this.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } else { + System.out.println(Thread.currentThread().getName() + "销售商品,剩余数量" + --product); + //消费货物之后唤醒生产者 + this.notifyAll(); + } + } +} + +//生产者 +class Product implements Runnable { + private Clerk clerk; + + public Product(Clerk clerk) { + this.clerk = clerk; + } + + @Override + public void run() { + for (int i = 0; i < 20; i++) { + try { + Thread.sleep(200);//网络延迟 + } catch (InterruptedException e) { + e.printStackTrace(); + } + clerk.stock(); + } + } +} + +//消费者 +class Consumer implements Runnable { + private Clerk clerk; + + public Consumer(Clerk clerk) { + this.clerk = clerk; + } + + @Override + public void run() { + for (int i = 0; i < 20; i++) { + clerk.sale(); + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer2.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer2.java new file mode 100644 index 00000000..c9898d19 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer2.java @@ -0,0 +1,108 @@ +package cn.lastwhisper.concurrent.example.productconsumer.waitnotify; + +/** + * 生产者消费者案例(等待唤醒机制),使用synchronize+Object的wait和notify; + * 1.有问题版本1:等待了唤醒不了 + * 1.1前置知识:sleep放弃CPU执行权,不释放锁;wait释放CPU执行权,释放锁 + * 1.2问题产生原因: + * 此时状态:product=0;消费者线程剩余循环次数=1;生产者线程剩余循环次数=2 + * (1).消费者线程拿到锁执行sale()到this.wait(); + * (2).生产者线程拿到锁执行get(),此时product=1;生产者线程剩余循环次数=1 + * 同时 this.notifyAll()唤醒消费者线程; + * (3).消费者线程接着this.wait()之后执行,此时product=1;消费者线程剩余循环次数=0;---消费者线程不会再执行 + * (4).生产者线程拿到锁执行get(),此时product=1,执行this.wait();---没有线程唤醒生产者线程 + * 1.3解决:除去else + * 2.有问题版本2:spurious wakeups 虚假唤醒(JDK API在Object的wait方法中有提到) + * 2.1问题产生原因: + * 此时状态:多个线程同时消费、同时生产时; + * (1)两个消费者线程同时进入sale()被wait; + * (2)一个生产者线程进入get(),一次++,然后执行notifyAll(), + * 将两个消费者线程都释放了,两次-- + * 2.2解决:使用while代替else + * @author lastwhisper + */ +public class TestProductAndConsumer2 { + public static void main(String[] args) { + Clerk2 clerk = new Clerk2(); + + new Thread(new Product2(clerk), "生产者A").start(); + new Thread(new Consumer2(clerk), "消费者B").start(); + new Thread(new Product2(clerk), "生产者C").start(); + new Thread(new Consumer2(clerk), "消费者D").start(); + } +} + +//店员 +class Clerk2 { + private int product = 0; + //进货(生产者线程调用) + public synchronized void get() { + while (product >= 1) { +// System.out.println("货物已满!"); + try { + //货物满了之后生产者等待 + this.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + System.out.println(Thread.currentThread().getName() + "添加商品,剩余数量" + ++product); + //生产货物之后唤醒消费者 + this.notifyAll(); + } + + //销售(消费者线程调用) + public synchronized void sale() { + while (product <= 0) { +// System.out.println("货物为空!"); + try { + //货物为空之后消费者等待 + this.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + System.out.println(Thread.currentThread().getName() + "销售商品,剩余数量" + --product); + //消费货物之后唤醒生产者 + this.notifyAll(); + + } +} + + +//生产者 +class Product2 implements Runnable { + private Clerk2 clerk; + + public Product2(Clerk2 clerk) { + this.clerk = clerk; + } + + @Override + public void run() { + for (int i = 0; i < 20; i++) { + try { + Thread.sleep(200);//网络延迟 + } catch (InterruptedException e) { + e.printStackTrace(); + } + clerk.get(); + } + } +} + +//消费者 +class Consumer2 implements Runnable { + private Clerk2 clerk; + + public Consumer2(Clerk2 clerk) { + this.clerk = clerk; + } + + @Override + public void run() { + for (int i = 0; i < 20; i++) { + clerk.sale(); + } + } +} 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/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/blockingqueue/SynchronousQueueDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/SynchronousQueueDemo.java new file mode 100644 index 00000000..248a241f --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/SynchronousQueueDemo.java @@ -0,0 +1,55 @@ +package cn.lastwhisper.concurrent.juc.blockingqueue; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; + +/** + * 阻塞队列SynchronousQueue演示 + * @author lastwhisper + */ +public class SynchronousQueueDemo { + + public static void main(String[] args) { + BlockingQueue blockingQueue = new SynchronousQueue<>(); + new Thread(() -> { + try { + System.out.println(Thread.currentThread().getName() + "\t put 1"); + blockingQueue.put("1"); + System.out.println(Thread.currentThread().getName() + "\t put 2"); + blockingQueue.put("2"); + System.out.println(Thread.currentThread().getName() + "\t put 3"); + blockingQueue.put("3"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }, "AAA").start(); + + new Thread(() -> { + try { + try { + TimeUnit.SECONDS.sleep(5); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(Thread.currentThread().getName() + "\t get " + blockingQueue.take()); + try { + TimeUnit.SECONDS.sleep(5); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(Thread.currentThread().getName() + "\t get " + blockingQueue.take()); + try { + TimeUnit.SECONDS.sleep(5); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(Thread.currentThread().getName() + "\t get " + blockingQueue.take()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }, "BBB").start(); + } +} + + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/ABADemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/ABADemo.java new file mode 100644 index 00000000..b4e1990a --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/ABADemo.java @@ -0,0 +1,63 @@ +package cn.lastwhisper.concurrent.juc.cas; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicStampedReference; + +/** + * @author lastwhisper + */ +public class ABADemo { + private static AtomicReference atomicReference = new AtomicReference<>(100); + private static AtomicStampedReference stampedReference = new AtomicStampedReference<>(100, 1); + + public static void main(String[] args) { + //System.out.println("===以下是ABA问题的产生==="); + //new Thread(() -> { + // atomicReference.compareAndSet(100, 101); + // atomicReference.compareAndSet(101, 100); + //}, "t1").start(); + // + //new Thread(() -> { + // try { + // // 先暂停1秒 保证完成ABA + // TimeUnit.SECONDS.sleep(1); + // System.out.println(atomicReference.compareAndSet(100, 2019) + "\t" + atomicReference.get()); + // } catch (InterruptedException e) { + // e.printStackTrace(); + // } + //}, "t2").start(); + System.out.println("===以下是ABA问题的解决==="); + + new Thread(() -> { + int stamp = stampedReference.getStamp(); + System.out.println(Thread.currentThread().getName() + "\t 第1次版本号" + stamp + "\t值是" + stampedReference.getReference()); + //暂停1秒钟t3线程 + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + stampedReference.compareAndSet(100, 101, stampedReference.getStamp(), stampedReference.getStamp() + 1); + System.out.println(Thread.currentThread().getName() + "\t 第2次版本号" + stampedReference.getStamp() + "\t值是" + stampedReference.getReference()); + stampedReference.compareAndSet(101, 100, stampedReference.getStamp(), stampedReference.getStamp() + 1); + System.out.println(Thread.currentThread().getName() + "\t 第3次版本号" + stampedReference.getStamp() + "\t值是" + stampedReference.getReference()); + }, "t3").start(); + + new Thread(() -> { + int stamp = stampedReference.getStamp(); + System.out.println(Thread.currentThread().getName() + "\t 第1次版本号" + stamp + "\t值是" + stampedReference.getReference()); + //保证线程3完成1次ABA + try { + TimeUnit.SECONDS.sleep(3); + } catch (InterruptedException e) { + e.printStackTrace(); + } + boolean result = stampedReference.compareAndSet(100, 2019, stamp, stamp + 1);//修改失败 + System.out.println(Thread.currentThread().getName() + "\t 修改成功否" + result + "\t最新版本号" + stampedReference.getStamp()); + System.out.println("最新的值\t" + stampedReference.getReference()); + }, "t4").start(); + + } +} 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/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/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/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/lock/SpinLockDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/SpinLockDemo.java new file mode 100644 index 00000000..a269a7bf --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/SpinLockDemo.java @@ -0,0 +1,59 @@ +package cn.lastwhisper.concurrent.juc.lock; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + * 自旋锁 + * @author lastwhisper + */ +public class SpinLockDemo { + private AtomicReference atomicReference = new AtomicReference<>(); + + // 上锁 + public void lock() { + Thread thread = Thread.currentThread(); + // 自旋 + while (!atomicReference.compareAndSet(null, thread)) { + + } + } + + // 解锁 + public void unlock() { + Thread thread = Thread.currentThread(); + atomicReference.compareAndSet(thread, null); + } + + public static void main(String[] args) throws InterruptedException { + SpinLockDemo spinLock = new SpinLockDemo(); + new Thread(new Runnable() { + @Override + public void run() { + spinLock.lock(); + System.out.println(Thread.currentThread().getName()+"\t 获取锁"); + try { + System.out.println(Thread.currentThread().getName()+"\t 搞事情"); + TimeUnit.SECONDS.sleep(3); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + spinLock.unlock(); + System.out.println(Thread.currentThread().getName()+"\t 释放锁"); + } + } + }, "t1").start(); + TimeUnit.SECONDS.sleep(1); + new Thread(new Runnable() { + @Override + public void run() { + + spinLock.lock(); + System.out.println(Thread.currentThread().getName()+"\t 获取锁"); + System.out.println(Thread.currentThread().getName()+"\t 搞事情"); + spinLock.unlock(); + System.out.println(Thread.currentThread().getName()+"\t 释放锁"); + } + }, "t2").start(); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestLock.java new file mode 100644 index 00000000..946048a4 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestLock.java @@ -0,0 +1,47 @@ +package cn.lastwhisper.concurrent.juc.lock; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 用于解决多线程安全性问题的方式: + * 1.synchronize:隐式锁JVM指令集底层支持的锁 + * 1.同步代码块 + * 2.同步方法 + * 2.Lock:显式锁,JDK实现的锁,需要手动lock、unlock + * @author lastwhisper + */ +public class TestLock { + public static void main(String[] args) { + Ticket ticket = new Ticket(); + new Thread(ticket, "一号窗口").start(); + new Thread(ticket, "二号窗口").start(); + new Thread(ticket, "三号窗口").start(); + } +} + +class Ticket implements Runnable { + private int tick = 100; + private Lock lock = new ReentrantLock(); + + @Override + public void run() { + while (true) { + lock.lock(); + try { + if (tick > 0) { + Thread.sleep(50);//放大线程安全性问题 + System.out.println(Thread.currentThread().getName() + " 剩余票数:" + --tick); + } else { + break; + } + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + } + +} + 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/lock/TestReadWriteLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestReadWriteLock.java new file mode 100644 index 00000000..e0aeefbc --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestReadWriteLock.java @@ -0,0 +1,95 @@ +package cn.lastwhisper.concurrent.juc.lock; + +import java.time.Duration; +import java.time.Instant; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * 读写锁:在读多写少的情景 + * 写写/读写 需要“互斥” + * 读读 不需要互斥 + * @author lastwhisper + */ +public class TestReadWriteLock { + // 互斥锁 + private static Lock lock = new ReentrantLock(); + // 读写锁 + private static ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private static Lock readLock = readWriteLock.readLock(); + private static Lock writeLock = readWriteLock.writeLock(); + // 闭锁 + private static CountDownLatch latch = new CountDownLatch(20); + // 共享数据 + private int value = 0; + + public static void main(String[] args) throws InterruptedException { + + TestReadWriteLock rwl = new TestReadWriteLock(); + // 读线程执行的主体 + Runnable readThread = new Runnable() { + @Override + public void run() { + rwl.handleRead(readLock); + //rwl.handleRead(lock); + latch.countDown(); + } + }; + // 写线程执行的主体 + Runnable writeThread = new Runnable() { + @Override + public void run() { + rwl.handleWrite(writeLock, new Random().nextInt()); + //rwl.handleWrite(lock, new Random().nextInt()); + latch.countDown(); + } + }; + Instant start = Instant.now(); + // 20次读写操作 + for (int i = 0; i < 18; i++) { + new Thread(readThread).start(); + } + for (int i = 18; i < 20; i++) { + new Thread(writeThread).start(); + } + latch.await(); + Instant end = Instant.now(); + // 读写锁耗时:504 (18个读线程100;2个写线程400;线程上下文切换4) + // 互斥锁耗时:2212 (18个读线程1800;2个写线程400;线程上下文切换12) + System.out.println("20次读写耗时:" + Duration.between(start, end).toMillis()); + } + + // 读取文件 + public Object handleRead(Lock lock) { + lock.lock(); + try { + // 模拟读业务耗时 + Thread.sleep(100); + + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + return value; + } + + // 写入文件 + public void handleWrite(Lock lock, int writeVal) { + lock.lock(); + try { + // 模拟写业务耗时 + Thread.sleep(200); + value = writeVal; + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + +} \ 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/ExchangerDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/ExchangerDemo.java new file mode 100644 index 00000000..7decabed --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/ExchangerDemo.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.concurrent.juc.tools; + +import java.util.concurrent.Exchanger; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * 交换器 + * @author lastwhisper + */ +public class ExchangerDemo { + private static Exchanger exchanger = new Exchanger(); + + public static void main(String[] args) { + ExecutorService executorService = Executors.newFixedThreadPool(2); + //python + executorService.execute(() -> { + try { + String python = exchanger.exchange("Hello Python"); + System.out.println("python说:" + python); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + //java + executorService.execute(() -> { + try { + System.out.println("python 走出来"); + TimeUnit.SECONDS.sleep(3); + String java = exchanger.exchange("Hello Java"); + System.out.println("java说:" + java); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + } +} 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 new file mode 100644 index 00000000..ac5b7e72 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCountDownLatch.java @@ -0,0 +1,70 @@ +package cn.lastwhisper.concurrent.juc.tools; + +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 { + // 线程池并行执行任务 + private static ExecutorService threadPool = Executors.newFixedThreadPool(10); + + public static void main(String[] args) throws InterruptedException, ExecutionException { + + CountDownLatch latch = new CountDownLatch(5); + + 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); + } + System.out.println("等待所有线程执行完毕"); + latch.await(); + // 对每个线程执行结果进行汇总 + List allReportData = new ArrayList<>(); + for (Future future : futureList) { + allReportData.add(future.get()); + } + + System.out.println(allReportData); + + // 关闭线程池 + threadPool.shutdown(); + } +} + +class Report implements Callable { + private CountDownLatch latch; + private String month; + + public Report(CountDownLatch latch, String month) { + this.latch = latch; + this.month = month; + } + + @Override + 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/juc/tools/TestCyclicBarrier.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCyclicBarrier.java new file mode 100644 index 00000000..f9691d03 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCyclicBarrier.java @@ -0,0 +1,51 @@ +package cn.lastwhisper.concurrent.juc.tools; + +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; + +/** + * + * @author lastwhisper + */ +public class TestCyclicBarrier { + public static void main(String[] args) { + CyclicBarrier cyclicBarrier = new CyclicBarrier(5); + CyclicBarrierDemo cbd = new CyclicBarrierDemo(cyclicBarrier); + for (int i = 0; i < 5; i++) { + new Thread(cbd).start(); + } + //CyclicBarrier是可重用的 + try { + Thread.sleep(6000); + System.out.println("--------------------重用CyclicBarrier--------------------"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + for (int i = 0; i < 5; i++) { + new Thread(cbd).start(); + } + } +} + +class CyclicBarrierDemo implements Runnable { + private CyclicBarrier cyclicBarrier; + + public CyclicBarrierDemo(CyclicBarrier cyclicBarrier) { + this.cyclicBarrier = cyclicBarrier; + } + + @Override + public void run() { + System.out.println("线程 " + Thread.currentThread().getName() + " 查询数据开始..."); + try { + Thread.sleep(1000); + System.out.println("线程 " + Thread.currentThread().getName() + " 查询数据结束..."); + cyclicBarrier.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (BrokenBarrierException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCyclicBarrier2.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCyclicBarrier2.java new file mode 100644 index 00000000..ba5cad44 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCyclicBarrier2.java @@ -0,0 +1,87 @@ +package cn.lastwhisper.concurrent.juc.tools; + +import java.util.Random; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; + +/** + * 循环栅栏:让一组线程等待至某个状态之后再全部同时执行 + * @author lastwhisper + */ +public class TestCyclicBarrier2 { + public static void main(String[] args) { + int n = 10; + Thread[] soldiers = new Thread[n]; + boolean flag = false; + CyclicBarrier cyclicBarrier = new CyclicBarrier(n, new BarrierAction(flag, n)); + System.out.println("集合队伍!!!"); + for (int i = 0; i < n; i++) { + System.out.println("士兵 " + i + " 报道"); + soldiers[i] = new Thread(new Soldier(cyclicBarrier, "士兵 " + i)); + soldiers[i].start(); + if (i == 6) { + soldiers[i].interrupt(); + } + //for循环还未执行完毕,最开始几个线程已经await,CyclicBarrier中的count已经开始计算 + } + } +} + +// CyclicBarrier等待完毕后执行的代码 +class BarrierAction implements Runnable { + boolean flag; + int n; + + public BarrierAction(boolean flag, int n) { + this.flag = flag; + this.n = n; + } + + @Override + public void run() { + System.out.println("被调用"); + if (flag) { + System.out.println("司令:[士兵" + n + "个,任务完成!]"); + } else { + System.out.println("司令:[士兵" + n + "个,集合完成!]"); + flag = true; + } + } +} + +class Soldier implements Runnable { + private String soldierName; + private CyclicBarrier cyclic; + + public Soldier(CyclicBarrier cyclic, String soldierName) { + this.cyclic = cyclic; + this.soldierName = soldierName; + } + + @Override + public void run() { + try { + //等待所有士兵到齐 + //await调用dowait,在dowait中count==0时会调用command.run(); + cyclic.await(); + //士兵开始执行任务 + doWork(); + //等待所有士兵完成任务 + cyclic.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (BrokenBarrierException e) { + e.printStackTrace(); + } + } + + void doWork() { + try { + Thread.sleep(Math.abs(new Random().nextInt() % 10000)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(soldierName + ":完成任务"); + } +} + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestSemaphore.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestSemaphore.java new file mode 100644 index 00000000..4c905357 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestSemaphore.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.concurrent.juc.tools; + +import java.util.Random; +import java.util.concurrent.Semaphore; + +/** + * 信号量:限定某几个线程访问同一资源 + * @author lastwhisper + */ +public class TestSemaphore { + public static void main(String[] args) { + // 3个车位 + Semaphore semaphore = new Semaphore(3); + // 7辆车 + for (int i = 0; i < 7; i++) { + SemaphoreDemo semaphoreDemo = new SemaphoreDemo(i, semaphore); + new Thread(semaphoreDemo).start(); + } + } +} + +class SemaphoreDemo implements Runnable { + private int num; + private Semaphore semaphore; + + public SemaphoreDemo(int num, Semaphore semaphore) { + this.num = num; + this.semaphore = semaphore; + } + + @Override + public void run() { + try { + semaphore.acquire(); + System.out.println(num + " 号车辆,进入停车场,占用一个停车位"); + Thread.sleep(new Random().nextInt(2000)); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + semaphore.release(); + System.out.println(num + " 号车辆,离开停车场"); + } + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..4f68ee58 --- /dev/null +++ b/java-basic/design-pattern/README.md @@ -0,0 +1,87 @@ +> 设计模式源码地址: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) + + +# 4. 进阶 + + 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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\350\243\205\351\245\260\350\200\205\346\250\241\345\274\217\357\274\210\344\272\214\357\274\211.md" "b/java-basic/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\243\205\351\245\260\350\200\205\346\250\241\345\274\217\357\274\210\344\272\214\357\274\211.md" similarity index 100% rename from "design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\243\205\351\245\260\350\200\205\346\250\241\345\274\217\357\274\210\344\272\214\357\274\211.md" rename to "java-basic/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\243\205\351\245\260\350\200\205\346\250\241\345\274\217\357\274\210\344\272\214\357\274\211.md" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" 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/java-basic/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" similarity index 100% rename from "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" rename to "java-basic/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" diff --git a/java-basic/design-pattern/pom.xml b/java-basic/design-pattern/pom.xml new file mode 100644 index 00000000..5523f3eb --- /dev/null +++ b/java-basic/design-pattern/pom.xml @@ -0,0 +1,303 @@ + + + + 4.0.0 + + cn.lastwhisper + 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 + + + + 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 + + + + junit + junit + 4.13 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.7 + 1.7 + + + + + + \ No newline at end of file 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/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v1/Handler.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v1/Handler.java new file mode 100644 index 00000000..03d964a1 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v1/Handler.java @@ -0,0 +1,26 @@ +package com.desgin.mashibing.chainofresponsibility.abstractImpl.v1; + +/** + * @author lastwhisper + */ +public abstract class Handler { + // + private Handler sucessor; + + public Handler getSucessor() { + return sucessor; + } + + public void setSucessor(Handler sucessor) { + this.sucessor = sucessor; + } + + public void execute(){ + handleProcess(); + if(sucessor!=null){ + sucessor.execute();; + } + } + + protected abstract void handleProcess(); +} 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/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/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CloseCourseVideoCommand.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CloseCourseVideoCommand.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CloseCourseVideoCommand.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CloseCourseVideoCommand.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Command.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Command.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Command.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Command.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CourseVideo.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CourseVideo.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CourseVideo.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CourseVideo.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/OpenCourseVideoCommand.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/OpenCourseVideoCommand.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/command/OpenCourseVideoCommand.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/OpenCourseVideoCommand.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Staff.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Staff.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Staff.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Staff.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Calculator.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Calculator.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Calculator.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Calculator.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Client.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Client.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Client.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Client.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/DivNode.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/DivNode.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/DivNode.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/DivNode.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ModNode.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ModNode.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ModNode.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ModNode.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/MulNode.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/MulNode.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/MulNode.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/MulNode.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Node.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Node.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Node.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Node.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/SymbolNode.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/SymbolNode.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/SymbolNode.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/SymbolNode.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ValueNode.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ValueNode.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ValueNode.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ValueNode.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/springel/SpringTest.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/springel/SpringTest.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/springel/SpringTest.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/springel/SpringTest.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Course.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Course.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Course.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Course.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregate.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregate.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregate.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregate.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregateImpl.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregateImpl.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregateImpl.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregateImpl.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIterator.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIterator.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIterator.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIterator.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIteratorImpl.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIteratorImpl.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIteratorImpl.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIteratorImpl.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/StudyGroup.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/StudyGroup.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/StudyGroup.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/StudyGroup.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/User.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/User.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/User.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/User.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Client.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Client.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Client.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Client.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/HouseOwner.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/HouseOwner.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/HouseOwner.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/HouseOwner.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Mediator.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Mediator.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Mediator.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Mediator.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/MediatorStructure.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/MediatorStructure.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/MediatorStructure.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/MediatorStructure.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Person.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Person.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Person.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Person.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Tenant.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Tenant.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Tenant.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Tenant.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Article.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Article.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Article.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Article.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMemento.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMemento.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMemento.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMemento.java diff --git a/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 similarity index 80% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMementoManager.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMementoManager.java index 7f636693..f8ac5a2e 100644 --- a/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/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Caretaker.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Caretaker.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Caretaker.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Caretaker.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Client.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Client.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Client.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Client.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Memento.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Memento.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Memento.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Memento.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Role.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Role.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Role.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Role.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Course.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Course.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Course.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Course.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Question.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Question.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Question.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Question.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Teacher.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Teacher.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Teacher.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Teacher.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEvent.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEvent.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEvent.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEvent.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEventTest.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEventTest.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEventTest.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEventTest.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observer.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observer.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observer.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observer.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observerable.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observerable.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observerable.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observerable.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/User.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/User.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/User.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/User.java diff --git a/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 similarity index 92% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/WechatServer.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/WechatServer.java index bf36b711..b65af3e9 100644 --- a/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/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoContext.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoContext.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoContext.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoContext.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoState.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoState.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoState.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoState.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PauseState.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PauseState.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PauseState.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PauseState.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PlayState.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PlayState.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PlayState.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PlayState.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/SpeedState.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/SpeedState.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/state/SpeedState.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/SpeedState.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/StopState.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/StopState.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/state/StopState.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/StopState.java 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 new file mode 100644 index 00000000..e748f33c --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/Test.java @@ -0,0 +1,24 @@ +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/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/EmptyPromotionStrategy.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/EmptyPromotionStrategy.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/EmptyPromotionStrategy.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/FanXianPromotionStrategy.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/FanXianPromotionStrategy.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/FanXianPromotionStrategy.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/FanXianPromotionStrategy.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/LiJianPromotionStrategy.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/LiJianPromotionStrategy.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/LiJianPromotionStrategy.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/LiJianPromotionStrategy.java diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/ManJianPromotionStrategy.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/ManJianPromotionStrategy.java new file mode 100644 index 00000000..e503709d --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/ManJianPromotionStrategy.java @@ -0,0 +1,9 @@ +package com.desgin.pattern.behavioral.strategy; + +public class ManJianPromotionStrategy 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/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionActivity.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionActivity.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionActivity.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategy.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategy.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategy.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategy.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategyFactory.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategyFactory.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategyFactory.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategyFactory.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/ACourse.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/ACourse.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/ACourse.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/ACourse.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/DesignPatternCourse.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/DesignPatternCourse.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/DesignPatternCourse.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/DesignPatternCourse.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/FECourse.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/FECourse.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/FECourse.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/FECourse.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Abstract.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Abstract.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Abstract.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Abstract.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_BaoCai.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_BaoCai.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_BaoCai.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_BaoCai.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_CaiXin.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_CaiXin.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_CaiXin.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_CaiXin.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/CodingCourse.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/CodingCourse.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/CodingCourse.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/CodingCourse.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Course.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Course.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Course.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Course.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/FreeCourse.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/FreeCourse.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/FreeCourse.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/FreeCourse.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/IVisitor.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/IVisitor.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/IVisitor.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/IVisitor.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Visitor.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Visitor.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Visitor.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Visitor.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Article.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Article.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Article.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Article.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/CourseFactory.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/CourseFactory.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/CourseFactory.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/CourseFactory.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaArticle.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaArticle.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaArticle.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaArticle.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaCourseFactory.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaCourseFactory.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaCourseFactory.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaCourseFactory.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaVideo.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaVideo.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaVideo.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaVideo.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonArticle.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonArticle.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonArticle.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonArticle.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonCourseFactory.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonCourseFactory.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonCourseFactory.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonCourseFactory.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonVideo.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonVideo.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonVideo.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonVideo.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Video.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Video.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Video.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Video.java diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Coach.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Coach.java new file mode 100644 index 00000000..66fb6040 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Coach.java @@ -0,0 +1,21 @@ +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/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Course.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/builder/Course.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Course.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseActualBuilder.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseActualBuilder.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseActualBuilder.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseActualBuilder.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseBuilder.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseBuilder.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseBuilder.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseBuilder.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/builder/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Test.java diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Course.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Course.java new file mode 100644 index 00000000..e421fede --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Course.java @@ -0,0 +1,75 @@ +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 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); + } + + + } + + public String toString() { + return "Course{" + + "courseName='" + courseName + '\'' + + ", coursePPT='" + coursePPT + '\'' + + ", courseVideo='" + courseVideo + '\'' + + ", courseArticle='" + courseArticle + '\'' + + ", courseQA='" + courseQA + '\'' + + '}'; + } +} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideo.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideo.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideo.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideo.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideoFactory.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideoFactory.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideoFactory.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideoFactory.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideo.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideo.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideo.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideo.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideoFactory.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideoFactory.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideoFactory.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideoFactory.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideo.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideo.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideo.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideo.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideoFactory.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideoFactory.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideoFactory.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideoFactory.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Video.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Video.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Video.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Video.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/VideoFactory.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/VideoFactory.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/VideoFactory.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/VideoFactory.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/A.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/A.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/A.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/A.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/B.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/B.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/B.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/B.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Resume.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Resume.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Resume.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Resume.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/JavaVideo.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/JavaVideo.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/JavaVideo.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/JavaVideo.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/PythonVideo.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/PythonVideo.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/PythonVideo.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/PythonVideo.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Video.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Video.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Video.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Video.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/VideoFactory.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/VideoFactory.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/VideoFactory.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/VideoFactory.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingleton.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingleton.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingleton.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingleton.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingletonTest.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingletonTest.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingletonTest.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingletonTest.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ContainerSingleton.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ContainerSingleton.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ContainerSingleton.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ContainerSingleton.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/EnumInstance.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/EnumInstance.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/EnumInstance.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/EnumInstance.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/HungrySingleton.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/HungrySingleton.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/HungrySingleton.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/HungrySingleton.java 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 new file mode 100644 index 00000000..eb3bd774 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazyDoubleCheckSingleton.java @@ -0,0 +1,26 @@ +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/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazySingleton.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazySingleton.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazySingleton.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/StaticInnerClassSingleton.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/StaticInnerClassSingleton.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/StaticInnerClassSingleton.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/StaticInnerClassSingleton.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/T.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/T.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/T.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/T.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test1.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test1.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test1.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test1.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadLocalInstance.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadLocalInstance.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadLocalInstance.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadLocalInstance.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadTest.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadTest.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadTest.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadTest.java diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton1.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton1.java new file mode 100644 index 00000000..bbe825f5 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton1.java @@ -0,0 +1,18 @@ +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/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton2.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton2.java new file mode 100644 index 00000000..eed8cf9c --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton2.java @@ -0,0 +1,21 @@ +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/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton3.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton3.java new file mode 100644 index 00000000..e4c76cc6 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton3.java @@ -0,0 +1,26 @@ +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/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton4.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton4.java new file mode 100644 index 00000000..58f5014e --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton4.java @@ -0,0 +1,20 @@ +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/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton5.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton5.java new file mode 100644 index 00000000..94b336f8 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton5.java @@ -0,0 +1,8 @@ +package com.desgin.pattern.creational.singleton.my; + +/** + * 懒汉式:枚举 + */ +public enum Singleton5 { + +} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adaptee.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adaptee.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adaptee.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adaptee.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adapter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adapter.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adapter.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adapter.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/ConcreteTarget.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/ConcreteTarget.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/ConcreteTarget.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/ConcreteTarget.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Target.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Target.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Target.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Target.java 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 new file mode 100644 index 00000000..672a267f --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Test.java @@ -0,0 +1,12 @@ +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/AC220.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/AC220.java similarity index 76% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/AC220.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/AC220.java index 2eeae6d2..3c393c1a 100644 --- a/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/exmaple/AC220.java @@ -1,4 +1,4 @@ -package com.desgin.pattern.structural.adapter; +package com.desgin.pattern.structural.adapter.exmaple; public class AC220 { public int outputAC220V() { 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/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/exmaple/PowerAdapter.java similarity index 78% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/PowerAdapter.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/PowerAdapter.java index a6ec40c5..56fdca4a 100644 --- a/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/exmaple/PowerAdapter.java @@ -1,5 +1,8 @@ -package com.desgin.pattern.structural.adapter; +package com.desgin.pattern.structural.adapter.exmaple; +/** + * 对象适配器 + */ public class PowerAdapter implements DC5 { private AC220 ac220 = new AC220(); @@ -7,7 +10,7 @@ public class PowerAdapter implements DC5 { @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/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adaptee.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adaptee.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adaptee.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adaptee.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adapter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adapter.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adapter.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adapter.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/ConcreteTarget.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/ConcreteTarget.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/ConcreteTarget.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/ConcreteTarget.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Target.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Target.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Target.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Target.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ABCBank.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ABCBank.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ABCBank.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ABCBank.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Account.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Account.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Account.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Account.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Bank.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Bank.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Bank.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Bank.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/DepositAccount.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/DepositAccount.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/bridge/DepositAccount.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/DepositAccount.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ICBCBank.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ICBCBank.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ICBCBank.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ICBCBank.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/SavingAccount.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/SavingAccount.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/bridge/SavingAccount.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/SavingAccount.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CatalogComponent.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CatalogComponent.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/composite/CatalogComponent.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CatalogComponent.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/composite/Course.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/composite/Course.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/composite/Course.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/composite/Course.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CourseCatalog.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CourseCatalog.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/composite/CourseCatalog.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CourseCatalog.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/composite/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/composite/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/composite/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/composite/Test.java diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/IODecorator.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/IODecorator.java new file mode 100644 index 00000000..09801b6b --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/IODecorator.java @@ -0,0 +1,20 @@ +package com.desgin.pattern.structural.decorator; + +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/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/Battercake.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/Battercake.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/Battercake.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/Battercake.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/BattercakeWithEgg.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/BattercakeWithEgg.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/BattercakeWithEgg.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/BattercakeWithEgg.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/BattercakeWithEggSausage.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/BattercakeWithEggSausage.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/BattercakeWithEggSausage.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/BattercakeWithEggSausage.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v1/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/ABattercake.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/ABattercake.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/ABattercake.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/ABattercake.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/AbstractDecorator.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/AbstractDecorator.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/AbstractDecorator.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/AbstractDecorator.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/Battercake.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/Battercake.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/Battercake.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/Battercake.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/EggDecorator.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/EggDecorator.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/EggDecorator.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/EggDecorator.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/SausageDecorator.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/SausageDecorator.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/SausageDecorator.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/SausageDecorator.java diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/Test.java new file mode 100644 index 00000000..3ce595af --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/decorator/v2/Test.java @@ -0,0 +1,12 @@ +package com.desgin.pattern.structural.decorator.v2; + +public class Test { + public static void main(String[] args) { + ABattercake aBattercake = new Battercake(); + + aBattercake = new EggDecorator(aBattercake); + aBattercake = new EggDecorator(aBattercake); + aBattercake = new SausageDecorator(aBattercake); + System.out.println(aBattercake.getDesc() + "价格为:" + aBattercake.cost()); + } +} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/facade/GiftExchangeService.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/GiftExchangeService.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/facade/GiftExchangeService.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/GiftExchangeService.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/facade/PointsGift.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/PointsGift.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/facade/PointsGift.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/PointsGift.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/facade/PointsPaymentService.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/PointsPaymentService.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/facade/PointsPaymentService.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/PointsPaymentService.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/facade/QualifyService.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/QualifyService.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/facade/QualifyService.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/QualifyService.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/facade/ShippingService.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/ShippingService.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/facade/ShippingService.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/ShippingService.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/facade/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/facade/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/facade/Test.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Employee.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Employee.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Employee.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Employee.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/EmployeeFactory.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/EmployeeFactory.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/EmployeeFactory.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/EmployeeFactory.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Manager.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Manager.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Manager.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Manager.java diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Test.java diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/application/IntegerDemo.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/application/IntegerDemo.java new file mode 100644 index 00000000..38e6a226 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/application/IntegerDemo.java @@ -0,0 +1,38 @@ +package com.desgin.pattern.structural.flyweight.application; + +import org.junit.Test; + +import java.util.Properties; + +/** + * 修改IntegerCache + * -Djava.lang.Integer.IntegerCache.high=129 + * -XX:AutoBoxCacheMax=129 + * @author lastwhisper + */ +public class IntegerDemo { + // 测试IntegerCache + @Test + public void test1(){ + Integer a1 = 127;//Integer.valueOf(127); + Integer a2 = 127; + System.out.println(a1 == a2); + + Integer a3 = 129;//Integer.valueOf(129); + Integer a4 = 129; + System.out.println(a3 == a4); + + Integer a5 = new Integer(127); + Integer a6 = new Integer(127); + System.out.println(a5 == a6); + } + // + @Test + public void test2(){ + int one = 1; + int two = one + one; + System.out.println(two == 2); + System.out.println(Integer.valueOf(two) == 2); + System.out.println(new Integer(2) == 2); + } +} 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/design-pattern/src/main/java/com/desgin/principle/demeter/Boss.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/demeter/Boss.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/demeter/Boss.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/demeter/Boss.java diff --git a/design-pattern/src/main/java/com/desgin/principle/demeter/Course.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/demeter/Course.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/demeter/Course.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/demeter/Course.java diff --git a/design-pattern/src/main/java/com/desgin/principle/demeter/TeamLeader.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/demeter/TeamLeader.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/demeter/TeamLeader.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/demeter/TeamLeader.java diff --git a/design-pattern/src/main/java/com/desgin/principle/demeter/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/demeter/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/demeter/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/demeter/Test.java diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Bottom.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Bottom.java new file mode 100644 index 00000000..a23975ee --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Bottom.java @@ -0,0 +1,12 @@ +package com.desgin.principle.dependencyInversion.v1; + +/** + * @author lastwhisper + */ +public class Bottom { + private Tire tire; + + public Bottom() { + this.tire = new Tire(); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Car.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Car.java new file mode 100644 index 00000000..f4e59104 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Car.java @@ -0,0 +1,16 @@ +package com.desgin.principle.dependencyInversion.v1; + +/** + * @author lastwhisper + */ +public class Car { + private Framework framework; + + public Car() { + this.framework = new Framework(); + } + + public void run() { + System.out.println("汽车跑起来了"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Client.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Client.java new file mode 100644 index 00000000..ef6a4b9c --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Client.java @@ -0,0 +1,13 @@ +package com.desgin.principle.dependencyInversion.v1; + +/** + * @author lastwhisper + */ +public class Client { + public static void main(String[] args){ + // 改动一下轮胎(Tire)类,把它的尺寸变成动态,比较麻烦 + // 需要修改源代码 + Car car = new Car(); + car.run(); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Framework.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Framework.java new file mode 100644 index 00000000..706c2c6e --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Framework.java @@ -0,0 +1,12 @@ +package com.desgin.principle.dependencyInversion.v1; + +/** + * @author lastwhisper + */ +public class Framework { + private Bottom bottom; + + public Framework() { + this.bottom = new Bottom(); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Tire.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Tire.java new file mode 100644 index 00000000..2ba696f1 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v1/Tire.java @@ -0,0 +1,13 @@ +package com.desgin.principle.dependencyInversion.v1; + +/** + * 先设计tire + * @author lastwhisper + */ +public class Tire { + private int size; + + public Tire() { + this.size = 30; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Bottom.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Bottom.java new file mode 100644 index 00000000..23d96457 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Bottom.java @@ -0,0 +1,12 @@ +package com.desgin.principle.dependencyInversion.v2; + +/** + * @author lastwhisper + */ +public class Bottom { + private Tire tire; + + public Bottom(Tire tire) { + this.tire = tire; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Car.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Car.java new file mode 100644 index 00000000..4f1ab1aa --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Car.java @@ -0,0 +1,16 @@ +package com.desgin.principle.dependencyInversion.v2; + +/** + * @author lastwhisper + */ +public class Car { + private Framework framework; + + public Car(Framework framework) { + this.framework = framework; + } + + public void run() { + System.out.println("汽车跑起来了"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Client.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Client.java new file mode 100644 index 00000000..9230c923 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Client.java @@ -0,0 +1,17 @@ +package com.desgin.principle.dependencyInversion.v2; + +/** + * @author lastwhisper + */ +public class Client { + public static void main(String[] args){ + // 此时动态修改轮胎的大小不需要修改Car、Framework、Bottom、Tire的内部代码 + + // 这段初始化代码就是 控制反转容器 + Tire tire = new Tire(30); + Bottom bottom = new Bottom(tire); + Framework framework = new Framework(bottom); + Car car = new Car(framework); + car.run(); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Framework.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Framework.java new file mode 100644 index 00000000..1d7a86d7 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Framework.java @@ -0,0 +1,12 @@ +package com.desgin.principle.dependencyInversion.v2; + +/** + * @author lastwhisper + */ +public class Framework { + private Bottom bottom; + + public Framework(Bottom bottom) { + this.bottom = bottom; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Tire.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Tire.java new file mode 100644 index 00000000..bdc97a30 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/dependencyInversion/v2/Tire.java @@ -0,0 +1,13 @@ +package com.desgin.principle.dependencyInversion.v2; + +/** + * 先设计tire + * @author lastwhisper + */ +public class Tire { + private int size; + + public Tire(int size) { + this.size = size; + } +} diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Bird.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Bird.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Bird.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Bird.java diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Dog.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Dog.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Dog.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Dog.java diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IAnimalAction.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IAnimalAction.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IAnimalAction.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IAnimalAction.java diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IEatAnimalAction.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IEatAnimalAction.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IEatAnimalAction.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IEatAnimalAction.java diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IFlyAnimalAction.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IFlyAnimalAction.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IFlyAnimalAction.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IFlyAnimalAction.java diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/ISwimAnimalAction.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/ISwimAnimalAction.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/interfacesegregation/ISwimAnimalAction.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/ISwimAnimalAction.java diff --git a/design-pattern/src/main/java/com/desgin/principle/openclose/ICourse.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/openclose/ICourse.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/openclose/ICourse.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/openclose/ICourse.java diff --git a/design-pattern/src/main/java/com/desgin/principle/openclose/JavaCourse.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/openclose/JavaCourse.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/openclose/JavaCourse.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/openclose/JavaCourse.java diff --git a/design-pattern/src/main/java/com/desgin/principle/openclose/JavaDiscountCourse.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/openclose/JavaDiscountCourse.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/openclose/JavaDiscountCourse.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/openclose/JavaDiscountCourse.java diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/openclose/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/openclose/Test.java new file mode 100644 index 00000000..4a3b22ba --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/openclose/Test.java @@ -0,0 +1,18 @@ +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/java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Bird.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Bird.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Bird.java diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/CourseImpl.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/CourseImpl.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/singleresponsibility/CourseImpl.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/CourseImpl.java diff --git a/java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/FlyBird.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/FlyBird.java new file mode 100644 index 00000000..9677c519 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/FlyBird.java @@ -0,0 +1,14 @@ +package com.desgin.principle.singleresponsibility; + +import java.util.HashMap; +import java.util.Map; + +/** + * Create by lastwhisper on 2019/1/22 + */ +public class FlyBird { + public void mainMoveMode(String birdName) { + System.out.println(birdName + "用翅膀飞"); + Map map = new HashMap(); + } +} diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourse.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourse.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourse.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourse.java diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseContent.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseContent.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseContent.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseContent.java diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseManager.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseManager.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseManager.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseManager.java diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Test.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Test.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Test.java diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/WalkBird.java b/java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/WalkBird.java similarity index 100% rename from design-pattern/src/main/java/com/desgin/principle/singleresponsibility/WalkBird.java rename to java-basic/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/WalkBird.java diff --git "a/design-pattern/uml/\350\256\276\350\256\241\346\250\241\345\274\217.mdj" "b/java-basic/design-pattern/uml/\350\256\276\350\256\241\346\250\241\345\274\217.mdj" similarity index 100% rename from "design-pattern/uml/\350\256\276\350\256\241\346\250\241\345\274\217.mdj" rename to "java-basic/design-pattern/uml/\350\256\276\350\256\241\346\250\241\345\274\217.mdj" 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/feature-jdk5/src/main/java/cn/lastwhisper/AutoBox.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/AutoBox.java new file mode 100644 index 00000000..f7375452 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/AutoBox.java @@ -0,0 +1,18 @@ +package cn.lastwhisper; + +/** + * jdk5新特性:自动拆箱与装箱 + * 语法糖,使开发的效率更高 + * IntegerCache缓存池,享元模式 + * @author lastwhisper + */ +public class AutoBox { + + public static void main(String[] args) { + // 语法糖 + //Integer it = 555;//自动装箱 + //int i = it;//自动拆箱 + + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/StaticImport.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/StaticImport.java new file mode 100644 index 00000000..b5cb690a --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/StaticImport.java @@ -0,0 +1,18 @@ +package cn.lastwhisper; + +import static java.lang.Math.abs; +import static java.lang.Math.*; +/** + * jdk5新特性:静态导入 + * @author lastwhisper + */ +public class StaticImport { + public static void main(String[] args) { + // 正常使用 + System.out.println(Math.min(3, 9)); + System.out.println(Math.abs(3 - 9)); + // 使用静态导入 + System.out.println(min(3, 9)); + System.out.println(abs(3 - 9)); + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/VariableParameter.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/VariableParameter.java new file mode 100644 index 00000000..bcc1ffff --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/VariableParameter.java @@ -0,0 +1,34 @@ +package cn.lastwhisper; + +/** + * jdk5新特性:可变参数+增强for循环 + * @author lastwhisper + */ +public class VariableParameter { + public static void main(String[] args) { + System.out.println(add(10, 20)); + System.out.println(add(10, 20, 30)); + System.out.println(add(10, 20, 30, 40)); + } + + /** + * 1. "..."表示可变参数,只能放在参数列表的最后位置 + * 2. "..."前后有无空格都行 + * 3. 编译器为可变参数隐式的创建一个数组,在方法中以数组的形式使用 + * + * @param args + * @return int + */ + public static int add(int... args) { + int sum = 0; + //for (int i = 0; i < args.length; i++) { + // sum += args[i]; + //} + // 增强for循环;每次循环的结果,可以使用修饰符,如使用final修饰即可作为匿名内部类的参数 + for (int arg : args) { + sum += arg; + } + return sum; + } + +} 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/feature-jdk5/src/main/java/cn/lastwhisper/enums/EnumTest.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/EnumTest.java new file mode 100644 index 00000000..db9424b8 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/EnumTest.java @@ -0,0 +1,80 @@ +package cn.lastwhisper.enums; + +import java.util.Arrays; + +/** + * jdk5新特性:枚举类型 + * @author lastwhisper + */ +public class EnumTest { + + public enum WeekDay2 { + Monday(1), Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday; + + /** + * 枚举类构造器: + * 1.必须放到枚举属性之后(所有属性、方法都要放到枚举属性之后) + * 2.必须是私有构造器 + * 3.默认调用无参构造,也可以显示在枚举属性上调用 + */ + private WeekDay2() { + System.out.println("无参构造"); + } + + private WeekDay2(int day) { + System.out.println("有参构造,参数:" + day); + } + } + + public enum TrafficLamp { + // 信号灯枚举属性 + Green(40) { + @Override + public TrafficLamp nextLamp() { + return Yellow; + } + }, Yellow(5) { + @Override + public TrafficLamp nextLamp() { + return Red; + } + }, Red(30) { + @Override + public TrafficLamp nextLamp() { + return Green; + } + }; + + private int time; + + private TrafficLamp(int time) { + this.time = time; + } + + public abstract TrafficLamp nextLamp(); + } + + public static void main(String[] args) { + // 枚举类型:编译时必须使用规定的值 + + // 自己实现枚举类的功能 + //WeekDay monday = WeekDay.Monday; + //WeekDay tuesday = monday.nextDay(); + //System.out.println(tuesday.toString()); + + // 使用抽象方法将nextDay中的if.else语句转为一个个独立的类 + //WeekDay1 monday = WeekDay1.Monday; + //WeekDay1 thesday = monday.nextDay(); + //System.out.println(thesday.toString()); + + // 使用枚举类 + WeekDay2 monday = WeekDay2.Monday; + System.out.println(monday); + System.out.println(monday.name()); + System.out.println(monday.ordinal());// 下标 + // java.lang.Enum.valueOf 从map去拿性能不差的 + System.out.println(WeekDay2.valueOf("Thursday1"));// 静态方法 + System.out.println(Arrays.toString(WeekDay2.values()));// 静态方法 + + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay.java new file mode 100644 index 00000000..00802dde --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay.java @@ -0,0 +1,57 @@ +package cn.lastwhisper.enums; + +/** + * 实现枚举功能 + * @author lastwhisper + */ +public class WeekDay { + // 周一至周日 + public static final WeekDay Monday = new WeekDay(); + public static final WeekDay Tuesday = new WeekDay(); + public static final WeekDay Wednesday = new WeekDay(); + public static final WeekDay Thursday = new WeekDay(); + public static final WeekDay Friday = new WeekDay(); + public static final WeekDay Saturday = new WeekDay(); + public static final WeekDay Sunday = new WeekDay(); + + // 私有构造器,禁止创建对象 + private WeekDay() { + } + + public WeekDay nextDay() { + if (this == Monday) { + return Tuesday; + } else if (this == Tuesday) { + return Wednesday; + } else if (this == Wednesday) { + return Thursday; + } else if (this == Thursday) { + return Friday; + } else if (this == Friday) { + return Saturday; + } else if (this == Saturday) { + return Sunday; + } else { + return Sunday; + } + } + + public String toString() { + if (this == Monday) { + return "Monday"; + } else if (this == Tuesday) { + return "Tuesday"; + } else if (this == Wednesday) { + return "Wednesday"; + } else if (this == Thursday) { + return "Thursday"; + } else if (this == Friday) { + return "Friday"; + } else if (this == Saturday) { + return "Saturday"; + } else { + return "Sunday"; + } + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay1.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay1.java new file mode 100644 index 00000000..9a5b67c0 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay1.java @@ -0,0 +1,76 @@ +package cn.lastwhisper.enums; + +/** + * 实现枚举功能 + * @author lastwhisper + */ +public abstract class WeekDay1 { + // 使用抽象方法将nextDay中的if.else语句转为一个个独立的类 + public static final WeekDay1 Monday = new WeekDay1() { + @Override + public WeekDay1 nextDay() { + return Tuesday; + } + }; + public static final WeekDay1 Tuesday = new WeekDay1() { + @Override + public WeekDay1 nextDay() { + return Wednesday; + } + }; + public static final WeekDay1 Wednesday = new WeekDay1() { + @Override + public WeekDay1 nextDay() { + return Thursday; + } + }; + public static final WeekDay1 Thursday = new WeekDay1() { + @Override + public WeekDay1 nextDay() { + return Friday; + } + }; + public static final WeekDay1 Friday = new WeekDay1() { + @Override + public WeekDay1 nextDay() { + return Saturday; + } + }; + public static final WeekDay1 Saturday = new WeekDay1() { + @Override + public WeekDay1 nextDay() { + return Sunday; + } + }; + public static final WeekDay1 Sunday = new WeekDay1() { + @Override + public WeekDay1 nextDay() { + return this; + } + }; + + // 私有构造器,禁止创建对象 + private WeekDay1() { + } + + public abstract WeekDay1 nextDay(); + + public String toString() { + if (this == Monday) { + return "Monday"; + } else if (this == Tuesday) { + return "Tuesday"; + } else if (this == Wednesday) { + return "Wednesday"; + } else if (this == Thursday) { + return "Thursday"; + } else if (this == Friday) { + return "Friday"; + } else if (this == Saturday) { + return "Saturday"; + } else { + return "Sunday"; + } + } + +} 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/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic1.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic1.java new file mode 100644 index 00000000..4bfc3489 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic1.java @@ -0,0 +1,49 @@ +package cn.lastwhisper.generic; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * jdk5新特性:泛型 + * @author lastwhisper + */ +public class Generic1 { + public static void main(String[] args) throws Exception { + // 1.泛型问题引入 + //ArrayList collections = new ArrayList(); + //collections.add(1); + //collections.add(1L); + //collections.add("abc"); + //int i = (Integer) collections.get(1);//编译要强制类型转换且运行时出错! + + // 2.泛型是给编译器看的 + ArrayList collection2 = new ArrayList(); + ArrayList collection3 = new ArrayList(); + System.out.println(collection2.getClass() == collection3.getClass()); + // 使用反射将String值放到ArrayList中 + collection3.getClass().getMethod( + "add", Object.class).invoke(collection3, "字符串"); + System.out.println(collection3.get(0)); + + // 3.通配符“?”,不知道泛型是什么 + printCollection(collection3); + + } + + //public static void printCollection(Collection cols) { + // for (Object col : cols) { + // System.out.println(col); + // } + // cols.add("字符串");//没错 + // //cols = new HashSet();//错误 + //} + + public static void printCollection(Collection cols) { + for (Object col : cols) { + System.out.println(col); + } + //cols.add("string");//错误 + cols.size(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic2.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic2.java new file mode 100644 index 00000000..6602709b --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic2.java @@ -0,0 +1,62 @@ +package cn.lastwhisper.generic; + +import java.util.Arrays; + +/** + * 自定义泛型模板 + * @author lastwhisper + */ +public class Generic2 { + public static void main(String[] args) { + + // 泛型推断的一般原则,用于返回泛型参数中的交集,且泛型参数必须为引用类型 + // 3 自动装箱 Integer 5 自动装箱Integer 所以 推断出Integer + Integer i = add(3, 3); + //Float f = add(3, 3.5); + // 3 自动装箱Integer str1 String 共有的交集,都是Object + Object o = add(3, "asdasdasd"); + + swap(new String[]{"a", "b", "c", "d"}, 2, 3); + //swap(new int[]{1, 2, 3, 4}, 2, 3);//只有引用类型才能作为泛型方法的实际参数 + + // 泛型练习题 + Object obj = "字符串"; + String str = convert(obj); + + String[] strings = new String[10]; + fillArray(strings, obj); + System.out.println(Arrays.toString(strings)); + + + } + + // 1.编写一个泛型方法,自动将Object类型的对象转换成其他类型。 + private static T convert(Object obj) { + return (T) obj; + } + + // 2.定义一个方法,可以将任意类型的数组中的所有元素填充为相应类型的某个对象。 + private static void fillArray(T[] arr, T obj) { + for (int i = 0; i < arr.length; i++) { + arr[i] = obj; + } + } + + // 采用自定泛型方法的方式打印出任意参数化类型的集合中的所有内容。 + private static void printArray(T[] t) { + for (int i = 0; i < t.length; i++) { + System.out.println("ele[" + i + "] = " + t[i]); + } + } + + private static void swap(T[] arr, int i, int j) { + T t = arr[i]; + arr[i] = arr[j]; + arr[j] = t; + } + + private static T add(T x, T y) { + return null; + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic3.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic3.java new file mode 100644 index 00000000..573691e6 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic3.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.generic; + +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 获取变量泛型类型 + * @author lastwhisper + */ +public class Generic3 { + + private List dates = new ArrayList(); + + // 通过变量本身是无法知道自身的泛型是啥,因为泛型在编译过后被擦除了。 + // 可以通过方法获取参数的泛型 + //https://www.cnblogs.com/homeword/p/7460594.html + public static void main(String[] args) throws Exception { + // 1.获取方法 + Method method = Generic3.class.getDeclaredMethod("showDate", List.class); + // 2.获取带泛型的参数类型 java.util.List + Type[] types = method.getGenericParameterTypes(); + // 3.获取ParameterizedType + ParameterizedType pType = (ParameterizedType) types[0]; + // 4.获取实际类型参数 + System.out.println(((Class) (pType.getActualTypeArguments()[0])).getName()); + + //System.out.println("showDate(" + // + ((Class) pType.getRawType()).getName() + "<" + // + ((Class) (pType.getActualTypeArguments()[0])).getName() + // + ">)" ); + } + + public void showDate(List dates) { + for (Date date : dates) { + System.out.println(date); + } + } + + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDao.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDao.java new file mode 100644 index 00000000..37002119 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDao.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.generic.Generic4; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; + +/** + * 通用泛型DAO模板 + * @author lastwhisper + */ +public interface BaseDao { + + void save(T t); + + void delete(int id); + + void delete(T t); + + void update(T t); + + T findById(int id); + + List findByConditions(String conditions); + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDaoImpl.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDaoImpl.java new file mode 100644 index 00000000..261eae36 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDaoImpl.java @@ -0,0 +1,58 @@ +package cn.lastwhisper.generic.Generic4; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; + +/** + * 通用泛型DAO模板 + * @author lastwhisper + */ +public class BaseDaoImpl implements BaseDao { + + protected Class clazz; + + public BaseDaoImpl() { + // 1.获取对象对应的父类的类型 + Type baseDaoClass = this.getClass().getGenericSuperclass(); + // 2.转成带参数,即泛型的类型 + ParameterizedType pType = (ParameterizedType) baseDaoClass; + // 3.获取参数泛型类型数组 + Type[] types = pType.getActualTypeArguments(); + // 4.由于我们的BaseDao的泛型参数里只有一个类型T,因此数组的第一个元素就是类型T的实际上的类型 + clazz = (Class) types[0]; + System.out.println("clazz = " + this.clazz); + } + + @Override + public void save(T t) { + System.out.println("save:" + t); + } + + @Override + public void delete(int id) { + System.out.println("delete id:" + id); + } + + @Override + public void delete(T t) { + System.out.println("delete:" + t); + } + + @Override + public void update(T t) { + System.out.println("update:" + t); + } + + @Override + public T findById(int id) { + System.out.println("findById:" + id); + return null; + } + + @Override + public List findByConditions(String conditions) { + System.out.println("findByConditions:" + conditions); + return null; + } +} 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/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/PersonDaoImpl.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/PersonDaoImpl.java new file mode 100644 index 00000000..9ca57f70 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/PersonDaoImpl.java @@ -0,0 +1,10 @@ +package cn.lastwhisper.generic.Generic4; + +/** + * extends BaseDaoImpl让通用模板知道你的泛型参数是啥,并且可以使用通用的方法 + * implements PersonDao是为了面向接口编程、以及更好的整合Spring + * @author lastwhisper + */ +public class PersonDaoImpl extends BaseDaoImpl implements PersonDao { + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/IntrospectorTest.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/IntrospectorTest.java new file mode 100644 index 00000000..7c51edea --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/IntrospectorTest.java @@ -0,0 +1,82 @@ +package cn.lastwhisper.introspection; + +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; + +/** + * 内省 + * JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。 + * 如果要你自己去通过getX方法来访问私有的x,怎么做,有一定难度吧? + * 用内省这套api操作JavaBean比用普通类的方式更方便。 + * + */ +public class IntrospectorTest { + // https://blog.csdn.net/jiangyu1013/article/details/75280962 + public static void main(String[] args) { + Point point = new Point(2, 5); + String proName = "x"; + int newVlaue = 10; + try { + // 不使用内省 + setPropertyForExample(point, proName, newVlaue); + Object x = getPropertyForExample(point, proName); + System.out.println(x); + // 使用内省 + //setProperty(point, proName, newVlaue); + //Object x = getProperty(point, proName); + // System.out.println(x); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + // 不使用内省,需要 "x"-->"X"-->"setX" + private static void setPropertyForExample(Object obj, String proName, int newVlaue) throws Exception { + String methodName; + if (proName.length() == 1) { + methodName = "set" + proName.toUpperCase(); + } else { + methodName = "set" + proName.substring(0, 1).toUpperCase() + proName.substring(1); + } + Method method = obj.getClass().getMethod(methodName, Integer.class); + method.invoke(obj, newVlaue); + } + + private static Object getPropertyForExample(Object obj, String proName) throws Exception { + String methodName; + if (proName.length() == 1) { + methodName = "get" + proName.toUpperCase(); + } else { + methodName = "get" + proName.substring(0, 1).toUpperCase() + proName.substring(1); + } + Method method = obj.getClass().getMethod(methodName); + return method.invoke(obj); + } + + private static void setProperty(Object obj, String proName, int newVlaue) throws Exception { + PropertyDescriptor proDescriptor = new PropertyDescriptor(proName, Point.class); + Method methodSetX = proDescriptor.getWriteMethod(); + methodSetX.invoke(obj, newVlaue); + } + + private static Object getProperty(Object obj, String proName) throws Exception { + PropertyDescriptor proDescriptor = new PropertyDescriptor(proName, Point.class); + Method methodGetX = proDescriptor.getReadMethod(); + return methodGetX.invoke(obj); + } + + private static Object getProperty1(Object obj, String proName) throws Exception { + BeanInfo beanInfo = Introspector.getBeanInfo(Point.class); + PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); + for (PropertyDescriptor pd : pds) { + if (pd.getName().equals(proName)) { + Method method = pd.getReadMethod(); + return method.invoke(obj); + } + } + return null; + } +} \ No newline at end of file diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/Point.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/Point.java new file mode 100644 index 00000000..2ab6ebb0 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/Point.java @@ -0,0 +1,42 @@ +package cn.lastwhisper.introspection; + +/** + * JavaBean + * JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。 + * + */ +public class Point { + + private Integer x; + private Integer y; + + public Point(Integer x, Integer y) { + super(); + this.x = x; + this.y = y; + } + + public Integer getX() { + return x; + } + + public void setX(Integer x) { + this.x = x; + } + + public Integer getY() { + return y; + } + + public void setY(Integer y) { + this.y = y; + } + + @Override + public String toString() { + return "Point{" + + "x=" + x + + ", y=" + y + + '}'; + } +} \ No newline at end of file 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/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBlockingNIO.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBlockingNIO.java new file mode 100644 index 00000000..7a885014 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBlockingNIO.java @@ -0,0 +1,104 @@ +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.FileChannel; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +/* + * 一、使用 NIO 完成网络通信的三个核心: + * + * 1. 通道(Channel):负责连接 + * + * java.nio.channels.Channel 接口: + * |--SelectableChannel + * |--SocketChannel + * |--ServerSocketChannel + * |--DatagramChannel + * + * |--Pipe.SinkChannel + * |--Pipe.SourceChannel + * + * 2. 缓冲区(Buffer):负责数据的存取 + * + * 3. 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况 + * + */ +public class TestBlockingNIO { + + //客户端 + @Test + public void client() throws IOException{ + //1. 获取通道 + SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898)); + + FileChannel inChannel = FileChannel.open(Paths.get("/Users/kaisui/Downloads/1.csv"), StandardOpenOption.READ); + + //2. 分配指定大小的缓冲区 + ByteBuffer buf = ByteBuffer.allocate(1024); + + //3. 读取本地文件,并发送到服务端 + while(inChannel.read(buf) != -1){ + buf.flip(); + sChannel.write(buf); + 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(); + } + + //服务端 + @Test + public void server() throws IOException{ + //1. 获取通道 + ServerSocketChannel ssChannel = ServerSocketChannel.open(); + + FileChannel outChannel = FileChannel.open(Paths.get("/Users/kaisui/Downloads/2.csv"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); + + //2. 绑定连接 + ssChannel.bind(new InetSocketAddress(9898)); + + //3. 获取客户端连接的通道 + SocketChannel sChannel = ssChannel.accept(); + + //4. 分配指定大小的缓冲区 + ByteBuffer buf = ByteBuffer.allocate(1024); + + //5. 接收客户端的数据,并保存到本地 + while(sChannel.read(buf) != -1){ + buf.flip(); + outChannel.write(buf); + buf.clear(); + } + + //发送反馈给客户端 + buf.put("服务端接收数据成功".getBytes()); + buf.flip(); + sChannel.write(buf); + + //6. 关闭通道 + sChannel.close(); + outChannel.close(); + ssChannel.close(); + + } + +} \ No newline at end of file diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBuffer.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBuffer.java new file mode 100644 index 00000000..3ad6f7df --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBuffer.java @@ -0,0 +1,146 @@ +package cn.lastwhisper.io.nio; + +import org.junit.Test; + +import java.nio.ByteBuffer; + +/* + * 一、缓冲区(Buffer):在java NIO 中负者数据的存储。缓冲区就是数组。用于存储不同类型的数据。 + * + * 根据数据类型的不同(boolean 除外),有以下 Buffer 常用子类: + * ByteBuffer + * CharBuffer + * ShortBuffer + * IntBuffer + * LongBuffer + * FloatBuffer + * DoubleBuffer + * + * 上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区 + * + * 二、缓冲区存取数据的两个核心方法: + * put():存入数据到缓冲区中 + * put(byte b):将给定单个字节写入缓冲区的当前位置 + * put(byte[] src):将 src 中的字节写入缓冲区的当前位置 + * put(int index, byte b):将指定字节写入缓冲区的索引位置(不会移动 position) + * get():获取缓存区中的数据 + * get() :读取单个字节 + * get(byte[] dst):批量读取多个字节到 dst 中 + * get(int index):读取指定索引位置的字节(不会移动 position) + * + * 三、缓冲区中的四个核心属性: + * capacity:容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。 + * limit:界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写) + * position:位置,表示缓冲区中正在操作数据的位置。 + * mark:标记,表示记录当前position位置。可以通过reset()恢复到mark的位置。 + * + * 0<=mark<=position<=limit<=capacity + * + * 四、直接缓冲区与非直接缓冲区: + * 非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM的内存中。 + * + * 直接缓冲区:通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率 + * 此方法返回的 缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区 。 + * 直接缓冲区的内容可以驻留在常规的垃圾回收堆之外. + * 将直接缓冲区主要分配给那些易受基础系统的本机 I/O 操作影响的大型、持久的缓冲区。 + * 最好仅在直接缓冲区能在程序性能方面带来明显好处时分配它们。 + * 直接字节缓冲区还可以过 通过FileChannel 的 map() 方法 将文件区域直接映射到内存中来创建 。该方法返回MappedByteBuffe + */ +public class TestBuffer { + + + @Test + public void test1() { + String str = "abced"; + // 1.分配一个指定大小的缓冲区 + ByteBuffer buffer = ByteBuffer.allocate(1024); + System.out.println("--------------allocate()----------------"); + System.out.println(buffer.position());//0 + System.out.println(buffer.limit());//1024 + System.out.println(buffer.capacity());//1024 + + // 2.利用put将数据存放到缓冲区 + buffer.put(str.getBytes()); + System.out.println("-------------put(5 byte)-------------"); + System.out.println(buffer.position());//5 + System.out.println(buffer.limit());//1024 + System.out.println(buffer.capacity());//1024 + + // 3.切换读取数据模式 + buffer.flip(); + System.out.println("--------------flip()------------"); + System.out.println(buffer.position());//0 + System.out.println(buffer.limit());//5 + System.out.println(buffer.capacity());//1024 + + // 4.利用get()读取缓冲区的数据 + System.out.println("--------------get()------------"); + byte[] dst = new byte[buffer.limit()]; + buffer.get(dst); + 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 + + //5.rewind():可重复读 + buffer.rewind(); + System.out.println("--------------rewind()------------"); + System.out.println(buffer.position());//0 + System.out.println(buffer.limit());//5 + System.out.println(buffer.capacity());//1024 + + //6.clear():清空缓冲区。但是缓冲区中的数据依然存在,但是处在“被遗忘”状态 + buffer.clear(); + + System.out.println("--------------clear()------------"); + System.out.println(buffer.position());//0 + System.out.println(buffer.limit());//1024 + System.out.println(buffer.capacity());//1024 + + System.out.println((char) buffer.get()); + } + + @Test + public void test2() { + String str = "abcde"; + ByteBuffer buf = ByteBuffer.allocate(1024); + buf.put(str.getBytes()); + + buf.flip(); + + byte[] dst = new byte[buf.limit()]; + buf.get(dst, 0, 2); + System.out.println(new String(dst, 0, 2)); + System.out.println(buf.position()); + + // mark 标记position + buf.mark(); + + buf.get(dst,2,2); + System.out.println(new String(dst, 0, 2)); + System.out.println(buf.position()); + + //reset() : 恢复到 mark 的位置 + buf.reset(); + System.out.println(buf.position()); + + //判断缓冲区中是否还有剩余数据 + if(buf.hasRemaining()){ + //获取缓冲区中可以操作的数量 + System.out.println(buf.remaining()); + } + + + } + + @Test + public void test3(){ + //分配直接缓冲区 + ByteBuffer buf = ByteBuffer.allocateDirect(1024); + ByteBuffer buf1 = ByteBuffer.allocate(1024); + // 是否是直接缓冲区 + System.out.println(buf.isDirect()); + System.out.println(buf1.isDirect()); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestChannel.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestChannel.java new file mode 100644 index 00000000..12acf27a --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestChannel.java @@ -0,0 +1,212 @@ +package cn.lastwhisper.io.nio; + +import org.junit.Test; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Map; +import java.util.Set; + +/* + * 一、通道(Channel):用于源节点与目标节点的连接。在java NIO中负责缓冲区中数据的传输。Channel本身不存储数据,需要配合缓冲区进行传输。 + * + * 二、通道的主要实现类 + * java.nio.channels.Channel 接口: + * |--FileChannel:用于读取、写入、映射和操作文件的通道。 + * |--SocketChannel:通过 TCP 读写网络中的数据。 + * |--ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。 + * |--DatagramChannel:通过 UDP 读写网络中的数据通道。 + * + * 三、获取通道 + * 1.java针对支持通道的类提供了getChannel()方法 + * 本地IO: + * FileInputStream/FileOutputStream + * RandomAccessFile + * + * 网络IO: + * Socket + * ServerSocket + * DatagramSocket + * + * 2.在JDK 1.7 中的NIO.2 针对各个通道提供了静态方法 open() + * 3.在JDK 1.7 中的NIO.2 的Files工具类的newByteChannel() + * + * 四、通道之间的数据传输 + * transferFrom() + * transferTo() + * + * 五、分散(Scatter)与聚集(Gather) + * 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中 + * 聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中 + * + * 六、字符集:Charset + * 编码:字符串-》字符数组 + * 解码:字符数组-》字符串 + */ +public class TestChannel { + + //利用通道完成文件的复制(非直接缓冲区) + @Test + public void test1() { + long start = System.currentTimeMillis(); + try ( + FileInputStream fis = new FileInputStream("d:/59035.zip"); + FileOutputStream fos = new FileOutputStream("d:/59036.zip"); + //1.获取通道 + FileChannel inChannel = fis.getChannel(); + FileChannel outChannel = fos.getChannel();) { + + //2.分配指定大小的缓冲区 + ByteBuffer buf = ByteBuffer.allocate(1024); + + //3.将通道中的数据存入缓冲区中 + while (inChannel.read(buf) != -1) { + //切换读取数据的模式 + buf.flip(); + //4.将缓冲区中的数据写入通道中 + outChannel.write(buf); + buf.clear();//清空缓冲区 + } + } catch (IOException e) { + e.printStackTrace(); + } + long end = System.currentTimeMillis(); + System.out.println("耗费时间:" + (end - start));//耗费时间:1094 + } + + //使用直接缓冲区完成文件的复制(内存映射文件) + @Test + public void test2() { + long start = System.currentTimeMillis(); + + try ( + //1.获取通道 + FileChannel inChannel = FileChannel.open(Paths.get("d:/59035.zip"), StandardOpenOption.READ); + FileChannel outChannel = FileChannel.open(Paths.get("d:/59036.zip"), + StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);) { + + //2.内存映射文件 + MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size()); + MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size()); + //3.直接对缓冲区进行数据的读写操作 + byte[] dst = new byte[inMappedBuf.limit()]; + inMappedBuf.get(dst); + outMappedBuf.put(dst); + } catch (IOException e) { + e.printStackTrace(); + } + + long end = System.currentTimeMillis(); + System.out.println("耗费的时间为:" + (end - start));//耗费的时间为:200 + } + + //通道之间的数据传输(直接缓冲区) + @Test + public void test3() { + long start = System.currentTimeMillis(); + + try ( + FileChannel inChannel = FileChannel.open(Paths.get("d:/59035.zip"), StandardOpenOption.READ); + FileChannel outChannel = FileChannel.open(Paths.get("d:/59036.zip"), + StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);) { + + inChannel.transferTo(0, inChannel.size(), outChannel); + outChannel.transferFrom(inChannel, 0, inChannel.size()); + } catch (IOException e) { + e.printStackTrace(); + } + long end = System.currentTimeMillis(); + System.out.println("耗费的时间为:" + (end - start));//耗费的时间为:147 + } + + // 分散和聚合 + @Test + public void test4() { + try ( + RandomAccessFile raf1 = new RandomAccessFile("d:/1.txt", "rw"); + RandomAccessFile raf2 = new RandomAccessFile("d:/2.txt", "rw"); + //1.获取通道 + FileChannel channel1 = raf1.getChannel(); + FileChannel channel2 = raf2.getChannel();) { + //2.分配指定大小的缓冲区 + ByteBuffer buf1 = ByteBuffer.allocate(512); + ByteBuffer buf2 = ByteBuffer.allocate(1024); + //3.分散读取 + ByteBuffer[] bufs = {buf1, buf2}; + channel1.read(bufs); + for (ByteBuffer buf : bufs) { + buf.flip(); + } + System.out.println(new String(bufs[0].array(), 0, bufs[0].limit())); + System.out.println("--------------------"); + System.out.println(new String(bufs[1].array(), 0, bufs[1].limit())); + + //4.聚集写入 + channel2.write(bufs); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + //输出支持的字符集 + @Test + public void test5() { + Map map = Charset.availableCharsets(); + Set> set = map.entrySet(); + + for (Map.Entry entry : set) { + System.out.println(entry.getKey() + "=" + entry.getValue()); + } + } + + //字符集 + @Test + public void test6() { + Charset cs1 = Charset.forName("GBK"); + //获取编码器 + CharsetEncoder ce = cs1.newEncoder(); + + //获取解码器 + CharsetDecoder cd = cs1.newDecoder(); + + CharBuffer cBuf = CharBuffer.allocate(1024); + cBuf.put("啦啦哈哈吧吧"); + cBuf.flip(); + + //编码 + ByteBuffer bBuf = null; + try { + bBuf = ce.encode(cBuf); + } catch (CharacterCodingException e) { + e.printStackTrace(); + } + + for (int i = 0; i < bBuf.limit(); i++) { + System.out.println(bBuf.get());//-64-78-64-78-71-2-7-2-80-55-80-55 + } + + //解码 + bBuf.flip(); + CharBuffer cBuf2 = null; + try { + cBuf2 = cd.decode(bBuf); + } catch (CharacterCodingException e) { + e.printStackTrace(); + } + System.out.println(cBuf2.toString());//啦啦哈哈吧吧 + } + +} + 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/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestPipe.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestPipe.java new file mode 100644 index 00000000..ff792a9d --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestPipe.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.io.nio; + +import org.junit.Test; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.Pipe; + +/** + * Java NIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。 + * 数据会被写到sink通道,从source通道读取。 + * @author lastwhisper + */ +public class TestPipe { + + @Test + public void test1() throws IOException { + //1.获取管道 + Pipe pipe = Pipe.open(); + //2.将缓冲区数据写入管道 + ByteBuffer buf = ByteBuffer.allocate(1024); + + Pipe.SinkChannel sinkChannel = pipe.sink(); + buf.put("通过单向管道发送数据".getBytes()); + buf.flip(); + sinkChannel.write(buf); + + //3.读取缓冲区中的数据 + Pipe.SourceChannel sourceChannel = pipe.source(); + buf.flip(); + int len = sourceChannel.read(buf); + System.out.println(new String(buf.array(), 0, len)); + + sourceChannel.close(); + sinkChannel.close(); + + } + +} 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/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOClient.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOClient.java new file mode 100644 index 00000000..0e6064a4 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOClient.java @@ -0,0 +1,16 @@ +package cn.lastwhisper.io.nio.v3; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + + +public class NIOClient { + public static void main(String[] args) throws IOException { + Socket socket = new Socket("127.0.0.1", 8080); + OutputStream out = socket.getOutputStream(); + String s = "hello world"; + out.write(s.getBytes()); + out.close(); + } +} \ No newline at end of file diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOServer.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOServer.java new file mode 100644 index 00000000..3a408401 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOServer.java @@ -0,0 +1,78 @@ +package cn.lastwhisper.io.nio.v3; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +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.Iterator; +import java.util.Set; + +/** + * 操作系统循环 + * @author lastwhisper + */ +public class NIOServer { + public static void main(String[] args) throws IOException { + // 1、创建选择器 + Selector selector = Selector.open(); + // 2、将通道注册到选择器上 + ServerSocketChannel ssChannel = ServerSocketChannel.open(); + // 设置非阻塞 + ssChannel.configureBlocking(false); + ssChannel.register(selector, SelectionKey.OP_ACCEPT); + // 3、监听事件 + ServerSocket serverSocket = ssChannel.socket(); + serverSocket.bind(new InetSocketAddress("127.0.0.1", 8080)); + + while (true) { + selector.select(); + Set keys = selector.selectedKeys(); + Iterator keyIterator = keys.iterator(); + // 5、事件循环 + while (keyIterator.hasNext()) { + SelectionKey key = keyIterator.next(); + // 4、获取到达的事件 + if (key.isAcceptable()) { + ServerSocketChannel ssChannel1 = (ServerSocketChannel) key.channel(); + // 服务器会为每个新连接创建一个 SocketChannel + SocketChannel socketChannel = ssChannel1.accept(); + socketChannel.configureBlocking(false); + // 这个新连接主要用于从客户端读取数据 + socketChannel.register(selector, SelectionKey.OP_READ); + } else if (key.isReadable()) { + SocketChannel sChannel = (SocketChannel) key.channel(); + System.out.println(readDataFromSocketChannel(sChannel)); + sChannel.close(); + } + keyIterator.remove(); + } + + } + + } + + private static String readDataFromSocketChannel(SocketChannel sChannel) throws IOException { + ByteBuffer buffer = ByteBuffer.allocate(1024); + StringBuilder data = new StringBuilder(); + while (true) { + buffer.clear(); + int n = sChannel.read(buffer); + if (n == -1) { + break; + } + buffer.flip(); + int limit = buffer.limit(); + char[] dst = new char[limit]; + for (int i = 0; i < limit; i++) { + dst[i] = (char) buffer.get(i); + } + data.append(dst); + buffer.clear(); + } + return data.toString(); + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/TCPClient.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/TCPClient.java new file mode 100644 index 00000000..97dfd6b7 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/TCPClient.java @@ -0,0 +1,31 @@ +package cn.lastwhisper.io.socket; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +/** + * @author lastwhisper + */ +public class TCPClient { + public static void main(String[] args) { + try (Socket socket = new Socket("127.0.0.1", 65000); + OutputStream os = socket.getOutputStream(); + InputStream is = socket.getInputStream();) { + // 将要传递给server的字符串转成byte数组,写到输出流中 + os.write("hello world".getBytes()); + 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); + + } catch (IOException e) { + e.printStackTrace(); + } + + } +} 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/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPClient.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPClient.java new file mode 100644 index 00000000..1760930c --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPClient.java @@ -0,0 +1,31 @@ +package cn.lastwhisper.io.socket; + +import java.io.IOException; +import java.net.*; + +/** + * @author lastwhisper + */ +public class UDPClient { + public static void main(String[] args) { + try { + DatagramSocket socket = new DatagramSocket(); + byte[] bytes = "Hello World".getBytes(); + // 将ip地址封装成address + InetAddress address = InetAddress.getByName("127.0.0.1"); + DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, 65001); + // 客户端发送数据到服务端 + socket.send(packet); + + // 客户端接收服务端回写的数据报 + byte[] data = new byte[100]; + DatagramPacket receivePacket = new DatagramPacket(data, data.length); + socket.receive(receivePacket); + + System.out.println(new String(receivePacket.getData(), 0, receivePacket.getLength())); + + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPServer.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPServer.java new file mode 100644 index 00000000..6ac137bf --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPServer.java @@ -0,0 +1,37 @@ +package cn.lastwhisper.io.socket; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.SocketException; + +/** + * @author lastwhisper + */ +public class UDPServer { + public static void main(String[] args) { + try { + + DatagramSocket socket = new DatagramSocket(65001); + byte[] buff = new byte[1024]; + DatagramPacket packet = new DatagramPacket(buff, buff.length); + // 接收客户端发送的内容,封装到DatagramPacket中 + socket.receive(packet); + + byte[] data = packet.getData(); + // 将字节流转为字符串(输出) + String content = new String(data, 0, packet.getLength()); + System.out.println(content); + // 将字符串转为字节流(回写给客户端) + byte[] bytes = String.valueOf(content.length()).getBytes(); + + DatagramPacket packetToClient = new DatagramPacket(bytes, bytes.length, packet.getAddress(), packet.getPort()); + + socket.send(packetToClient); + + } catch (IOException e) { + e.printStackTrace(); + } + + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectExecutMain.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectExecutMain.java new file mode 100644 index 00000000..140c48bb --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectExecutMain.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.reflect; + +import java.io.InputStream; +import java.lang.reflect.Method; +import java.util.Properties; + +/** + * @author lastwhisper + */ +public class ReflectExecutMain { + public static void main(String[] args) throws Exception { + //InputStream is = new FileInputStream("D:\\code\\GitRepository\\JavaNotes\\java-basic\\jdk5\\src\\config.properties"); + InputStream is = ReflectExecutMain.class.getClassLoader().getResourceAsStream("config.properties"); + + Properties properties = new Properties(); + properties.load(is); + String className = properties.getProperty("className"); + + Class clazz = Class.forName(className); + //Class clazz = Class.forName("cn.lastwhisper.jdk5.feature.reflect.TestArrayArguments"); + Method mainMethod = clazz.getMethod("main", String[].class); + System.out.println(mainMethod.invoke(null, (Object) new String[]{"arg1", "arg2", "arg3"})); + } +} + +class TestArrayArguments { + public static void main(String[] args) { + for (String arg : args) { + System.out.println("----------" + arg + "----------"); + } + } +} \ No newline at end of file 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/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForConstructor.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForConstructor.java new file mode 100644 index 00000000..554cb768 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForConstructor.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.reflect; + +import java.lang.reflect.Constructor; + +/** + * 反射之Constructor类 + * Constructor类代表某个类中的一个构造方法 + * + * @author lastwhisper + */ +public class ReflectForConstructor { + public static void main(String[] args) throws Exception { + Class clazz = Class.forName("java.lang.String"); + // 1. 得到某个类所有的构造方法 + Constructor[] constructors = clazz.getConstructors(); + // 2. 得到某一个构造方法 + // 得到String的以StringBuffer为参数的构造函数 + Constructor constructor = clazz.getConstructor(StringBuffer.class); + // 3. 创建实例对象 + // 3.1 通常方式 + String str1 = new String(new StringBuffer("new String")); + // 3.2 反射方式 constructor.newInstance与clazz.newInstance + String str2 = constructor.newInstance(new StringBuffer("constructor.newInstance String")); + } + + + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForField.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForField.java new file mode 100644 index 00000000..07cedfa5 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForField.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.reflect; + +import java.lang.reflect.Field; + +/** + * 反射之Field类 + * Field类代表某个类中的一个成员变量 + * @author lastwhisper + */ +public class ReflectForField { + public static void main(String[] args) throws Exception { + ReflectPoint pt1 = new ReflectPoint(10, 20); + // 访问x + Class clazz = pt1.getClass(); + Field fieldX = clazz.getField("x");//private、protected都看不到 + System.out.println(fieldX.get(pt1)); + // 访问y + Field fieldY = clazz.getDeclaredField("y"); + fieldY.setAccessible(true); + System.out.println(fieldY.get(pt1)); + + + + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForMethod.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForMethod.java new file mode 100644 index 00000000..69e0ee2a --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForMethod.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.reflect; + +import java.lang.reflect.Method; + +/** + * 反射之Method类 + * Method类代表某个类中的一个成员方法 + * @author lastwhisper + */ +public class ReflectForMethod { + public static void main(String[] args) throws Exception { + String str = "string"; + // 1. 获取String的charAt方法 + Class clazz = Class.forName("java.lang.String"); + Method charAtMethod = clazz.getMethod("charAt", int.class); + // 2. 调用方法 + // 2.1 通常方式 str.charAt(1); + // 2.2 反射方式 + // 如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法! + System.out.println(charAtMethod.invoke(str, 1)); + + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectPoint.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectPoint.java new file mode 100644 index 00000000..64dbff33 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectPoint.java @@ -0,0 +1,56 @@ +package cn.lastwhisper.reflect; + +import java.util.Objects; + +/** + * @author lastwhisper + */ +public class ReflectPoint { + private int x; + private int y; + + public ReflectPoint(int x, int y) { + this.x = x; + this.y = y; + } + + // 重载 + public boolean equals(ReflectPoint o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ReflectPoint that = (ReflectPoint) o; + return x == that.x && + y == that.y; + } + + // 重写 + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ReflectPoint that = (ReflectPoint) o; + return x == that.x && + y == that.y; + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return y; + } + + public void setY(int y) { + this.y = y; + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectToArray.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectToArray.java new file mode 100644 index 00000000..7f3412d0 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectToArray.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.reflect; + +import java.lang.reflect.Array; + +/** + * 反射操作数据 + * @author lastwhisper + */ +public class ReflectToArray { + + public static void main(String[] args) { + int[] a1 = new int[]{1, 2, 3}; + String str1 = "123"; + printObject(a1); + printObject(str1); + } + + public static void printObject(Object object) { + if (object.getClass().isArray()) { + int length = Array.getLength(object); + for (int i = 0; i < length; i++) { + Object arr = Array.get(object, i); + System.out.println(arr); + } + } else { + System.out.println(object); + } + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectUpdateField.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectUpdateField.java new file mode 100644 index 00000000..a7436a77 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectUpdateField.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.reflect; + +import java.lang.reflect.Field; + +/** + * 使用反射更新字段的值 + * @author lastwhisper + */ +public class ReflectUpdateField { + public String str1 = "ball"; + public String str2 = "basketball"; + public String str3 = "lastwhisper"; + + public static void main(String[] args) throws Exception { + ReflectUpdateField obj = new ReflectUpdateField(); + System.out.println("未修改前:" + obj); + + Class clazz = obj.getClass(); + Field[] fields = clazz.getFields(); + for (Field field : fields) { + if (field.getType() == String.class) { + String oldValue = (String) field.get(obj); + String newValue = oldValue.replace('b', '*'); + field.set(obj, newValue); + } + } + + System.out.println("修改后:" + obj); + } + + @Override + public String toString() { + return "ReflectUpdateField{" + + "str1='" + str1 + '\'' + + ", str2='" + str2 + '\'' + + ", str3='" + str3 + '\'' + + '}'; + } +} 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/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test2.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test2.java new file mode 100644 index 00000000..81ef993a --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test2.java @@ -0,0 +1,40 @@ +package cn.lastwhisper.serializable; + +import java.io.*; + +/** + * 不使用Transient关键字,使用父子类序列化特性使得字段不被序列化 + * @author lastwhisper + */ +public class Test2 { + public static void main(String[] args) throws IOException, ClassNotFoundException { + // 序列化存储对象 + B b1 = new B("admin", "132465"); + ObjectOutputStream out = new ObjectOutputStream( + new FileOutputStream("D:\\result.obj")); + out.writeObject(b1); + out.close(); + // 反序列化 + ObjectInputStream oin = new ObjectInputStream(new FileInputStream( + "D:\\result.obj")); + B b2 = (B) oin.readObject(); + oin.close(); + System.out.println(b2.username + " " + b2.pwd); + } +} + +class A { + protected String pwd; + + public A() { + } +} + +class B extends A implements Serializable { + protected String username; + + public B(String username, String pwd) { + this.username = username; + super.pwd = pwd; + } +} \ No newline at end of file diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test3.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test3.java new file mode 100644 index 00000000..bf7432f4 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test3.java @@ -0,0 +1,67 @@ +package cn.lastwhisper.serializable; + + +import java.io.*; + +/** + * @author lastwhisper + */ +public class Test3 implements Serializable{ + private static final long serialVersionUID = 1L; + + private String password = "pass"; + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + private void writeObject(ObjectOutputStream out) { + try { + ObjectOutputStream.PutField putFields = out.putFields(); + System.out.println("原密码:" + password); + password = "encryption";//模拟加密 + putFields.put("password", password); + System.out.println("加密后的密码" + password); + out.writeFields(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void readObject(ObjectInputStream in) { + try { + ObjectInputStream.GetField readFields = in.readFields(); + Object object = readFields.get("password", ""); + System.out.println("要解密的字符串:" + object.toString()); + password = "pass";//模拟解密,需要获得本地的密钥 + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + + } + + public static void main(String[] args) { + try { + ObjectOutputStream out = new ObjectOutputStream( + new FileOutputStream("D:\\result.obj")); + out.writeObject(new Test3()); + out.close(); + + ObjectInputStream oin = new ObjectInputStream(new FileInputStream( + "D:\\result.obj")); + Test3 t = (Test3) oin.readObject(); + System.out.println("解密后的字符串:" + t.getPassword()); + oin.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (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/feature-jdk8/src/main/java/cn/cunchang/annotation/MyAnnotations.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/MyAnnotations.java new file mode 100644 index 00000000..3b74e0e5 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/MyAnnotations.java @@ -0,0 +1,13 @@ +package cn.cunchang.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; + +@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})//可以修饰的目标 +@Retention(RetentionPolicy.RUNTIME)//生命周期 +public @interface MyAnnotations { + MyAnnotation[] value();// 重复注解的容器 +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/TestAnnotation.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/TestAnnotation.java new file mode 100644 index 00000000..b85751d3 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/TestAnnotation.java @@ -0,0 +1,30 @@ +package cn.cunchang.annotation; + +import org.junit.Test; + +import java.lang.reflect.Method; + +/** + * 可重复的注解及可用于类型的注解 + */ +public class TestAnnotation { + + //checker framework框架提供此注解 + private /*@NonNull*/ Object obj = null; + + @Test + public void test1() throws NoSuchMethodException, SecurityException { + Class clazz = TestAnnotation.class; + Method m1 = clazz.getMethod("show"); + MyAnnotation[] mas = m1.getAnnotationsByType(MyAnnotation.class); + for (MyAnnotation myAnnotation : mas) { + System.out.println(myAnnotation.value()); + } + } + + @MyAnnotation("Hello") + @MyAnnotation("world") + public void show(@MyAnnotation("abc") String str) { + + } +} \ No newline at end of file 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/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime.java new file mode 100644 index 00000000..7809980e --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime.java @@ -0,0 +1,153 @@ +package cn.cunchang.date; + +import org.junit.Test; + +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAdjusters; +import java.util.Set; + +/** + * 以前的时间API是线程不安全的,多线程对日期进行处理要加锁 + * + * LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。 + * 它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。 + */ +public class TestLocalDateTime { + + //1.LocalDate LocalTime LocalDateTime 用法一样,用于让人读的时间日期 + @Test + public void test1() { + //获取当前日期时间 + LocalDateTime ldt = LocalDateTime.now(); + System.out.println(ldt); + + //指定一个日期时间 + LocalDateTime ldt2 = LocalDateTime.of(2015, 10, 19, 13, 22, 33); + System.out.println(ldt2); + + LocalDateTime ldt3 = ldt.plusYears(2);//加2年 + System.out.println(ldt3); + + LocalDateTime ldt4 = ldt.minusMonths(2);//减2个月 + System.out.println(ldt4); + + System.out.println(ldt.getYear()); + System.out.println(ldt.getMonthValue()); + System.out.println(ldt.getDayOfMonth()); + System.out.println(ldt.getHour()); + System.out.println(ldt.getMinute()); + System.out.println(ldt.getSecond()); + + } + + //2.Instant:时间戳(以Unix元年: 1970年1月1日00:00:00到某个时间之间的毫秒值) + @Test + public void test2() { + Instant ins1 = Instant.now();//默认获取UTC时区的时间 + System.out.println(ins1); + + OffsetDateTime odt = ins1.atOffset(ZoneOffset.ofHours(8));//获取偏移日期时间,加8小时偏移 + System.out.println(odt); + + System.out.println(ins1.toEpochMilli());//获取与Unix元年间隔毫秒数 + + Instant ins2 = Instant.ofEpochSecond(60);//较Unix元年加60秒 + System.out.println(ins2);//1970-01-01T00:01:00Z + } + + //3.Duration:计算两个时间之间的间隔,Period:计算两个日期之间的间隔 + @Test + public void test3() { + Instant ins1 = Instant.now(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + Instant ins2 = Instant.now(); + Duration duration = Duration.between(ins1, ins2); + System.out.println(duration.toMillis());//1000 + + System.out.println("------------------------------"); + + LocalTime lt1 = LocalTime.now(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + LocalTime lt2 = LocalTime.now(); + System.out.println(Duration.between(lt1, lt2).toMillis());//1001 + + System.out.println("------------------------------"); + + LocalDate ld1 = LocalDate.of(2015, 1, 1); + LocalDate ld2 = LocalDate.now(); + Period period = Period.between(ld1, ld2); + System.out.println(period.getYears());//2 + System.out.println(period.getMonths());//6 + System.out.println(period.getDays());//19 + } + + //TemporalAdjuster:时间校验器 + @Test + public void test5() { + LocalDateTime ldt = LocalDateTime.now(); + System.out.println(ldt);//2017-07-20T19:28:57.822 + + LocalDateTime ldt2 = ldt.withDayOfMonth(10); + System.out.println(ldt2);//2017-07-10T19:28:57.822 + + LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));//调整为下个周日 + System.out.println(ldt3);//2017-07-23T19:31:39.479 + + //自定义:下一个工作日 + LocalDateTime ldt5 = ldt.with((l) -> { + LocalDateTime ldt4 = (LocalDateTime) l; + DayOfWeek dow = ldt4.getDayOfWeek();//获取当前星期 + if (dow.equals(DayOfWeek.FRIDAY)) {//如果是周5,下个工作日即加3天 + return ldt4.plusDays(3); + } else if (dow.equals(DayOfWeek.SATURDAY)) {//如果是周6,下个工作日即加2天 + return ldt4.plusDays(2); + } else { + return ldt4.plusDays(1);//其他,下个工作日即为明天 + } + }); + System.out.println(ldt5);//2017-07-21T19:37:05.533 + } + + //DateTimeFormatter:格式化时间/日期 + @Test + public void test6() { + DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE; + LocalDateTime ldt = LocalDateTime.now(); + + String strDate = ldt.format(dtf); + System.out.println(strDate); + + System.out.println("------------------------"); + + DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");//自定义格式化格式 + String strDate2 = dtf2.format(ldt); + System.out.println(strDate2);//2017年07月20日 19:49:53 + + LocalDateTime newDate = ldt.parse(strDate2, dtf2);//以指定格式解析字符串,重新获得LocalDateTime类型 + System.out.println(newDate);//2017-07-20T19:49:53 + } + + //ZonedDate、ZonedTime、ZonedDateTime + @Test + public void test7() { + //获取支持的所有时区 + Set set = ZoneId.getAvailableZoneIds(); + set.forEach(System.out::println); + + //获取指定时区的日期时间类型 + LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Europe/Monaco")); + System.out.println(ldt);//2017-07-20T14:01:23.417 + + LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Europe/Monaco")); + //获取带时区的时间类型 + ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Europe/Monaco")); + System.out.println(zdt);//2017-07-20T14:01:23.420+02:00[Europe/Monaco]//与UTC时间有2个小时的时差 + } +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime2.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime2.java new file mode 100644 index 00000000..0b7b671a --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime2.java @@ -0,0 +1,64 @@ +package cn.cunchang.date; + +import org.junit.Test; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +/** + * 日期字符串转Date + * @author lastwhisper + * @date 2019/10/25 + */ +public class TestLocalDateTime2 { + + @Test + public void testStringToLocalDate() { + DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy MM dd"); + String localTime = "2019 10 25"; + LocalDateTime ldt = LocalDateTime.parse(localTime, df); + System.out.println("String类型的时间转成LocalDateTime:" + ldt); + ////自定义格式化格式 + //DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd"); + //LocalDateTime ldt = LocalDateTime.parse("20191022", dtf); + //System.out.println(ldt); + } + + @Test + public void testStringToDate() { + String strDate = "20191022"; + //注意:SimpleDateFormat构造函数的样式与strDate的样式必须相符 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); + //必须捕获异常 + try { + Date date = simpleDateFormat.parse(strDate); + System.out.println(date); + } catch (ParseException px) { + px.printStackTrace(); + } + } + + // 日期之差 + @Test + public void test2() { + String strDate1 = "20191022"; + String strDate2 = "20191024"; + //注意:SimpleDateFormat构造函数的样式与strDate的样式必须相符 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); + //必须捕获异常 + try { + Date date1 = simpleDateFormat.parse(strDate1); + Date date2 = simpleDateFormat.parse(strDate2); + Instant instant1 = date1.toInstant(); + Instant instant2 = date2.toInstant(); + System.out.println(Duration.between(instant1, instant2).toDays()); + } catch (ParseException px) { + px.printStackTrace(); + } + } +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/interfa/MyInterface.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/interfa/MyInterface.java new file mode 100644 index 00000000..00a0cc28 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/interfa/MyInterface.java @@ -0,0 +1,25 @@ +package cn.cunchang.interfa; + +public interface MyInterface { + + default String getName() { + return "呵呵呵"; + } + + public static void show() { + System.out.println("接口中的静态方法"); + } + +} + +interface Named { + default String getName() { + return "hehehe"; + } +} + +class MyClass implements MyInterface, Named { + public String getName() { + return Named.super.getName(); + } +} \ No newline at end of file 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/feature-jdk8/src/main/java/cn/cunchang/lambda/MyFun.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/MyFun.java new file mode 100644 index 00000000..04d40788 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/MyFun.java @@ -0,0 +1,9 @@ +package cn.cunchang.lambda; + +/** + * @author lastwhisper + */ +@FunctionalInterface +public interface MyFun { + public Integer getValue(Integer num); +} 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/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda2.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda2.java new file mode 100644 index 00000000..397bcd3d --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda2.java @@ -0,0 +1,93 @@ +package cn.cunchang.lambda; + +import org.junit.Test; + +import java.util.Comparator; +import java.util.function.Consumer; + +/* + * 一、Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符 + * 箭头操作符将 Lambda 表达式拆分成两部分: + * + * 左侧:Lambda 表达式的参数列表 + * 右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体 + * + * 语法格式一:无参数,无返回值 + * () -> System.out.println("Hello Lambda!"); + * + * 语法格式二:有一个参数,并且无返回值 + * (x) -> System.out.println(x) + * + * 语法格式三:若只有一个参数,小括号可以省略不写 + * x -> System.out.println(x) + * + * 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句 + * Comparator com = (x, y) -> { + * System.out.println("函数式接口"); + * return Integer.compare(x, y); + * }; + * + * 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写 + * Comparator com = (x, y) -> Integer.compare(x, y); + * + * 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断” + * (Integer x, Integer y) -> Integer.compare(x, y); + * + * 上联:左右遇一括号省 + * 下联:左侧推断类型省 + * 横批:能省则省 + * + * 二、Lambda 表达式需要“函数式接口”的支持 + * 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰 + * 可以检查是否是函数式接口 + */ +public class TestLambda2 { + + @Test + public void test1() { + //通过匿名内部类的方式实现接口 + Runnable r = new Runnable() { + @Override + public void run() { + System.out.println("Hello World!"); + } + }; + r.run(); + + System.out.println("----------------------"); + //匿名内部类用代替匿名内部类 + Runnable r1 = () -> System.out.println("Hello Lambda!"); + r1.run(); + } + + @Test + public void test2() { + Consumer con = x -> System.out.println(x); + con.accept("尚硅谷牛逼"); + } + + @Test + public void test3() { + Comparator com = (x, y) -> { + System.out.println("函数式接口"); + return Integer.compare(x, y); + }; + } + + @Test + public void test4() { + Comparator comparator = (x, y) -> Integer.compare(x, y); + } + + @Test + public void test6() { + System.out.println(operation(100, x -> x * x)); + System.out.println(operation(100, y -> y + 200)); + + } + + public Integer operation(Integer num, MyFun myFun) { + return myFun.getValue(num); + } + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda3.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda3.java new file mode 100644 index 00000000..83212fc3 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda3.java @@ -0,0 +1,95 @@ +package cn.cunchang.lambda; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +/** + * + * java内置四大函数式接口 + * 为什么内置? + * 因为每次使用lambda都需要自己写一个函数式接口,但实际上只有极其特殊的情况 + * 才需要自己编写,其他的常见函数式接口java8内置了。 + * Consumer :消费型接口 + * void accept(T t); + * Supplier :供给型接口 + * T get(); + * Function :函数型接口 + * R apply(T t); + * Predicate :断言型接口 + * boolean test(T t); + * + */ +public class TestLambda3 { + + //Consumer 消费型接口: + @Test + public void test1() { + happy(1000, m -> System.out.println("消费:" + m + "元")); + } + + public void happy(double money, Consumer consumer) { + consumer.accept(money); + } + + //Supplier 供给型接口: + //需求:产生指定个数的整数,并放入集合中 + @Test + public void test2() { + List list = getNumList(10, () -> (int) (Math.random() * 100)); + for (Integer num : list) { + System.out.println(num); + } + } + + public List getNumList(Integer num, Supplier supplier) { + List list = new ArrayList<>(); + for (int i = 0; i < num; i++) { + list.add(supplier.get()); + } + return list; + } + + //Function 函数型接口: + @Test + public void test3() { + String newStr = strHandler("\t\t\t 啦啦啦德玛西亚 ", (str) -> str.trim()); + System.out.println(newStr); + + String subStr = strHandler("无与伦比,为杰沉沦", (str) -> str.substring(5, 9)); + System.out.println(subStr); + } + + //需求:处理字符串 + public String strHandler(String str, Function fun) { + return fun.apply(str); + } + + //Predicate 断言型接口: + @Test + public void test4() { + List list = Arrays.asList("Hello", "jj", "Lambda", "www", "ok"); + List strList = filterStr(list, (s) -> s.length() > 3); + for (String string : strList) { + System.out.println(string); + } + } + + //需求:将满足条件的字符串,放入集合中 + public List filterStr(List list, Predicate pre) { + List strList = new ArrayList<>(); + for (String str : list) { + if (pre.test(str)) { + strList.add(str); + } + } + return strList; + } + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestMethodRef.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestMethodRef.java new file mode 100644 index 00000000..b0059d00 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestMethodRef.java @@ -0,0 +1,97 @@ +package cn.cunchang.lambda; + +import org.junit.Test; + +import java.io.PrintStream; +import java.util.Comparator; +import java.util.function.*; + +/* + * 一、方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为方法引用时Lambda表达式的另一种表现形式) + * + * 主要有三种语法格式: + * 对象::实例方法名 + * 类::静态方法名 + * 类::实例方法名 + * + * 注意: + * 1、Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致! + * 2、若Lambda参数列表中的第一个参数是 实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method + * + * 二、构造器引用: + * 格式: + * ClassName::new + * + * 注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致! + * + * 三:数组引用: + * Type::new; + * + */ +public class TestMethodRef { + + // 对象::实例方法名 + @Test + public void test1() { + PrintStream ps = System.out; + Consumer con = x -> ps.println(x);//生成了一个实现了Consumer接口的类的对象 + + PrintStream ps1 = System.out; + Consumer con1 = ps1::println;//相当于上面,引用了ps对象的println()方法 + + Consumer con2 = System.out::println; + con2.accept("abcde"); + } + + @Test + public void test2() { + Employee employee = new Employee(); + Supplier sup = () -> employee.getName();//代替匿名内部类 + System.out.println(sup.get()); + + Supplier sup2 = employee::getName; + System.out.println(sup2.get()); + } + + //类::静态方法名 + @Test + public void test3() { + Comparator com = (x, y) -> Integer.compare(x, y); + Comparator com1 = Integer::compare; + } + + //类::实例方法名 + @Test + public void test4() { + BiPredicate bp = (x, y) -> x.equals(y); + BiPredicate bp2 = String::equals; + } + + // 构造器引用 + @Test + public void test5() { + Supplier sup = () -> new Employee(); + + // 构造器引用 + Supplier sup2 = Employee::new; + System.out.println(sup2.get()); + + Function fun2 = (x) -> new Employee(x); + System.out.println(fun2.apply(101)); + + BiFunction bf = Employee::new; + } + + // 数组引用 + @Test + public void test6() { + Function fun = (x) -> new String[x]; + System.out.println(fun.apply(10).length); + + Function fun2=String[]::new; + String[] str2=fun2.apply(20); + System.out.println(str2.length); + } + + +} 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/feature-jdk8/src/main/java/cn/cunchang/optional/Godness.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/Godness.java new file mode 100644 index 00000000..cd35a531 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/Godness.java @@ -0,0 +1,27 @@ +package cn.cunchang.optional; + +public class Godness { + + private String name; + + public Godness() { + } + + public Godness(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Godness [name=" + name + "]"; + } + +} 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/feature-jdk8/src/main/java/cn/cunchang/optional/NewMan.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/NewMan.java new file mode 100644 index 00000000..7efbd803 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/NewMan.java @@ -0,0 +1,36 @@ +package cn.cunchang.optional; + +import java.util.Optional; + +//注意:Optional 不能被序列化 +public class NewMan { + + private Optional godness = Optional.empty(); + + private Godness god; + + public NewMan() { + } + + public NewMan(Optional godness) { + this.godness = godness; + } + + public Optional getGod(){ + return Optional.of(god); + } + + public Optional getGodness() { + return godness; + } + + public void setGodness(Optional godness) { + this.godness = godness; + } + + @Override + public String toString() { + return "NewMan [godness=" + godness + "]"; + } + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/TestOptional.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/TestOptional.java new file mode 100644 index 00000000..210373a7 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/TestOptional.java @@ -0,0 +1,130 @@ +package cn.cunchang.optional; + +import cn.cunchang.stream.Employee; +import org.junit.Test; + +import java.util.Optional; + +/* + * 一、Optional 容器类:用于尽量避免空指针异常 + * Optional.of(T t) : 创建一个 Optional 实例 + * Optional.empty() : 创建一个空的 Optional 实例 + * Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例 + * isPresent() : 判断是否包含值 + * orElse(T t) : 如果调用对象包含值,返回该值,否则返回t + * orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值 + * map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty() + * flatMap(Function mapper):与 map 类似,要求返回值必须是Optional + */ +public class TestOptional { + + // Optional.of(T t) : 创建一个 Optional 实例 + @Test + public void test1() { + Optional op = Optional.of(new Employee()); + //Optional op1 = Optional.of(null); + Employee emp = op.get(); + System.out.println(emp); + } + + /** + * Optional.ofNullable(T t):若 t不为 null,创建 Optional 实例,否则创建空实例 + * Optional.empty() : 创建一个空的 Optional 实例 + */ + @Test + public void test2(){ + //Optional op = Optional.ofNullable(null); + //System.out.println(op.get()); + + Optional op1 = Optional.empty(); + System.out.println(op1.get()); + } + + /** + * isPresent() : 判断是否包含值 + * orElse(T t) : 如果调用对象包含值,返回该值,否则返回t + * orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回s获取的值 + */ + @Test + public void test3(){ + Optional op = Optional.ofNullable(null); + + if(op.isPresent()){ + System.out.println(op.get()); + } + + Employee emp = op.orElse(new Employee("张三")); + System.out.println(emp); + + Employee emp2 = op.orElseGet(() -> new Employee("李四")); + System.out.println(emp2); + } + + /** + * + * map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty() + * flatMap(Function mapper):与map类似,要求返回值必须是Optional + */ + @Test + public void test4(){ + Optional op = Optional.of(new Employee(101, "张三", 18, 9999.99)); + + Optional op2 = op.map(Employee::getName); + System.out.println(op2.get()); + + Optional op3 = op.flatMap((e) -> Optional.of(e.getName())); + System.out.println(op3.get()); + } + + /** + * 需求:获取一个男人心中女神的名字 + * 传统避免空指针异常 + */ + @Test + public void test5(){ + Man man = new Man(); + String name = getGodnessName(man); + System.out.println(name); + } + public String getGodnessName(Man man){ + if(man != null){ + Godness g = man.getGod(); + + if(g != null){ + return g.getName(); + } + } + return "苍老师"; + } + + //运用 Optional 的实体类 + @Test + public void test6(){ + Optional godness = Optional.ofNullable(new Godness("林志玲")); + + Optional op = Optional.ofNullable(new NewMan(godness)); + String name = getGodnessName2(op); + System.out.println(name); + } + + public String getGodnessName2(Optional man){ + return man.orElse(new NewMan()) + .getGodness() + .orElse(new Godness("苍老师")) + .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/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI2.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI2.java new file mode 100644 index 00000000..aeaec51c --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI2.java @@ -0,0 +1,144 @@ +package cn.cunchang.stream; + +import cn.cunchang.lambda.Employee; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/* + * 一、Stream API 的操作步骤: + * 1. 创建 Stream + * 2. 中间操作 + * 3. 终止操作(终端操作) + */ +public class TestStreamAPI2 { + + 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 ,true留下, 从流中排除某些元素。 + * limit——截断流,使其元素不超过给定数量。 + * skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 + * distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 + */ + //内部迭代:迭代操作由 Stream API 完成 + @Test + public void test1() { + //中间操作:不会执行任何操作 + Stream stream = employees.stream() + .filter((e) -> e.getAge() > 35); + + //终止操作:一次性执行全部内容,即 惰性求值 + stream.forEach(System.out::println); + } + + //外部迭代 + @Test + public void test2() { + Iterator it = employees.iterator(); + + while (it.hasNext()) { + System.out.println(it.next()); + } + } + + //发现“短路”只输出了两次,说明只要找到 2 个 符合条件的就不再继续迭代 + @Test + public void test3() { + employees.stream().filter(e -> { + System.out.println("短路"); + return e.getSalary() > 5000; + }) + .limit(2) + .forEach(System.out::println); + } + + @Test + public void test4() { + employees.parallelStream() + .filter(e -> e.getSalary() >= 5000)//false过滤 + //.skip(2) //跳过两个 + .forEach(System.out::println); + } + + @Test + public void test5() { + employees.stream() + .distinct()//去重,注意:需要Employee重写hashCode 和 equals 方法 + .forEach(System.out::println); + } + + /** + * 中间操作:映射 + * map--接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新元素。 + * flatMap--接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 + */ + @Test + public void test6() { + List list = Arrays.asList("aaa", "bbb", "ccc", "ddd"); + list.stream() + .map(String::toUpperCase) + .forEach(System.out::println); + + System.out.println("------------------------"); + //map和flatMap的关系 类似于 add(Object)和addAll(Collection coll) + Stream sm = list.stream().flatMap(TestStreamAPI2::filterCharacter); + sm.forEach(System.out::println); + + } + + public static Stream filterCharacter(String str) { + List list = new ArrayList<>(); + for (Character ch : str.toCharArray()) { + list.add(ch); + } + return list.stream(); + } + + /** + * 中间操作:排序 + * sorted()-自然排序(按照对象类实现Comparable接口的compareTo()方法 排序) + * sorted(Comparator com)-定制排序(Comparator) + */ + @Test + public void test7() { + // 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())) { + return e1.getName().compareTo(e2.getName()); + } else { + return e1.getAge().compareTo(e2.getAge()); + } + }).forEach(System.out::println); + + } + + + @Test + public void test8() { + List list = employees.stream().filter(e -> e.getSalary() >= 5000).collect(Collectors.toList()); + System.out.println(list.size()); + System.out.println(employees.size()); + } +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI3.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI3.java new file mode 100644 index 00000000..aa65b29f --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI3.java @@ -0,0 +1,254 @@ +package cn.cunchang.stream; + +import org.junit.Test; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/* + * 一、Stream API 的操作步骤: + * 1. 创建 Stream + * 2. 中间操作 + * 3. 终止操作(终端操作) + */ +public class TestStreamAPI3 { + + List employees = 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) + ); + + /** + * 终止操作:查找与匹配 + */ + @Test + public void test1() { + // allMatch-检查是否匹配所有元素 + boolean b1 = employees.stream() + .allMatch(e -> e.getStatus().equals(Status.BUSY)); + System.out.println(b1);//false + + // anyMatch-检查是否至少匹配一个元素 + boolean b2 = employees.stream() + .anyMatch(e -> e.getStatus().equals(Status.BUSY)); + System.out.println(b2);//true + + // noneMatch-检查是否没有匹配所有元素 + boolean b3 = employees.stream() + .noneMatch(e -> e.getStatus().equals(Status.BUSY)); + System.out.println(b3);//true + + // findFirst-返回第一个元素//Optional是Java8中避免空指针异常的容器类 + Optional op = employees.stream() + .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())) + .findFirst(); + System.out.println(op.get()); + + // findAny-返回当前流中的任意元素 + Optional op2 = employees.parallelStream() + .filter(e -> e.getStatus().equals(Status.FREE)) + .findAny(); + System.out.println(op2.get()); + + // count-返回流中元素的总个数 + Long count = employees.stream() + .count(); + System.out.println(count); + + // max-返回流中最大值 + Optional op3 = employees.stream() + .max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())); + System.out.println(op3.get()); + + // min-返回流中最小值 + Optional op4 = employees.stream() + .map(Employee::getSalary) + .min(Double::compare); + System.out.println(op4.get()); + + } + + /** + * 终止操作:归约 + * map和reduce的连接通常称为map-reduce 模式 + */ + @Test + public void test3() { + List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + Integer sum = list.stream() + .reduce(0, (x, y) -> x + y); + System.out.println(sum); + + System.out.println("--------------------------"); + + Optional op = employees.stream()//reduce(BinaryOperator b)//没有起始值,map返回可能为空,所以返回Optional类型 + .map(Employee::getSalary) + .reduce(Double::sum); + System.out.println(op.get()); + } + + /** + * 终止操作:收集 + * collect-将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。 + */ + @Test + public void test4() { + List list = employees.stream() + .map(Employee::getName) + .collect(Collectors.toList()); + list.forEach(System.out::println); + System.out.println("----------------------------"); + + Set set = employees.stream() + .map(Employee::getName) + .collect(Collectors.toSet()); + set.forEach(System.out::println); + System.out.println("----------------------------"); + + HashSet hs = employees.stream() + .map(Employee::getName) + .collect(Collectors.toCollection(HashSet::new)); + hs.forEach(System.out::println); + } + + @Test + public void test5() { + // 求和 + //long count1 = employees.stream().count(); + System.out.println("--------------求和--------------"); + Long count2 = employees.stream().collect(Collectors.counting()); + System.out.println(count2); + + + //平均值 + System.out.println("--------------平均值--------------"); + Double avg = employees.stream(). + collect(Collectors.averagingDouble(Employee::getSalary)); + System.out.println(avg); + + //总和 + System.out.println("--------------总和--------------"); + Double sum = employees.stream() + .collect(Collectors.summingDouble(Employee::getSalary)); + System.out.println(sum); + + //最大值 + System.out.println("--------------最大值--------------"); + Optional max = employees.stream() + .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); + System.out.println(max.get()); + + //最小值 + System.out.println("--------------最小值--------------"); + Optional min = employees.stream() + .map(Employee::getSalary) + .collect(Collectors.minBy(Double::compare)); + System.out.println(min.get()); + } + + // 分组 + @Test + public void test6() { + + // 根据状态分组 +// 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()); + System.out.println(entry.getValue().getSum()); + } + } + + // 多级分组 + @Test + public void test7() { + // 多级分组,先根据状态进行分组,再根据年龄分组 + Map>> map2 = employees.stream() + .collect(Collectors.groupingBy(Employee::getStatus, + Collectors.groupingBy(e -> { + if (e.getAge() <= 35) { + return "青年"; + } else if (e.getAge() <= 50) { + return "中年"; + } else { + return "老年"; + } + }))); + for (Map.Entry>> entry : map2.entrySet()) { + System.out.println("----------------多级分组:根据状态分组-----------------"); + System.out.println(entry.getKey()); + Map> innerMap = entry.getValue(); + for (Map.Entry> innerEntry : innerMap.entrySet()) { + System.out.println("------------------------多级分组:根据年龄分组---------"); + System.out.println(innerEntry.getKey()); + innerEntry.getValue().forEach(System.out::println); + } + } + } + + // 分区 + @Test + public void test8() { + //分区 + Map> map3 = employees.stream() + .collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000)); + for (Map.Entry> entry : map3.entrySet()) { + System.out.println("----------------根据状态分区-----------------"); + System.out.println(entry.getKey()); + entry.getValue().forEach(System.out::println); + } + } + + // + @Test + public void test9() { + String str = employees.stream() + .map(Employee::getName) + .collect(Collectors.joining("," , "----", "----")); + + System.out.println(str); + } + + @Test + public void test10(){ + Optional sum = employees.stream() + .map(Employee::getSalary) + .collect(Collectors.reducing(Double::sum)); + System.out.println(sum.get()); + } + +} 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/feature-jdk8/src/main/java/cn/cunchang/stream/example/TestTransaction.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/TestTransaction.java new file mode 100644 index 00000000..2127b44e --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/TestTransaction.java @@ -0,0 +1,130 @@ +package cn.cunchang.stream.example; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; + +/** + * @author lastwhisper + */ +public class TestTransaction { + List transactions = null; + + @Before + public void before() { + Trader raoul = new Trader("Raoul", "Cambridge"); + Trader mario = new Trader("Mario", "Milan"); + Trader alan = new Trader("Alan", "Cambridge"); + Trader brian = new Trader("Brian", "Cambridge"); + + transactions = Arrays.asList( + new Transaction(brian, 2011, 300), + new Transaction(raoul, 2012, 1000), + new Transaction(raoul, 2011, 400), + new Transaction(mario, 2012, 710), + new Transaction(mario, 2012, 700), + new Transaction(alan, 2012, 950) + ); + } + + /** + * 1. 找出2011年发生的所有交易,并按交易额排序(从低到高) + * (e1,e2)->e1.getValue().compareTo(e2.getValue()))——》sorted(Comparator.comparing(Transaction::getValue)) + */ + @Test + public void test1() { + transactions.stream() + .filter(x -> x.getYear() == 2011) + .sorted(Comparator.comparing(Transaction::getValue)) + .forEach(System.out::println); + } + + /** + * 2. 交易员都在哪些不同的城市工作过? + */ + @Test + public void test2() { + transactions.stream() + .map(e -> e.getTrader().getCity()) + .distinct() + .forEach(System.out::println); + } + + /** + * 3. 查找所有来自剑桥的交易员,并按姓名排序 + * x->x.getTrader()——》Transaction::getTrader + * (e1,e2)->e1.getName().compareTo(e2.getName())——》Comparator.comparing(Trader::getName) + */ + @Test + public void test3() { + transactions.stream() + .filter(x -> x.getTrader().getCity().equals("Cambridge")) + .distinct() + .map(Transaction::getTrader) + .sorted(Comparator.comparing(Trader::getName)) + .forEach(System.out::println); + } + + /** + * 4. 返回所有交易员的姓名字符串,按字母顺序排序 + * (e1,e2)->e1.compareTo(e2) + */ + @Test + public void test4() { + transactions.stream() + .map(x -> x.getTrader().getName()) + .sorted(Comparator.comparing(x -> x)) + .forEach(System.out::println); + } + + + /** + * 5. 有没有交易员是在米兰工作的? + */ + @Test + public void test5() { + boolean match = transactions.stream() + .anyMatch(x -> x.getTrader().getCity().equals("Milan")); + System.out.println(match); + } + + /** + * 6. 打印生活在剑桥的交易员的所有交易额 + */ + @Test + public void test6() { + Optional reduce = transactions.stream() + .filter((e) -> e.getTrader().getCity().equals("Cambridge")) + .map(Transaction::getValue) + .reduce(Integer::sum); + System.out.println(reduce.get()); + } + + /** + * 7. 所有交易中,最高的交易额是多少 + */ + @Test + public void test7() { + transactions.stream() + .map(Transaction::getValue) + .max(Integer::compare); + + Optional max = transactions.stream() + .max(Comparator.comparing(Transaction::getValue)); + System.out.println(max.get().getValue()); + } + + /** + * 8. 找到交易额最小的交易 + */ + + @Test + public void test8() { + Optional min = transactions.stream().min(Comparator.comparing(Transaction::getValue)); + System.out.println(min.get()); + } +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Trader.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Trader.java new file mode 100644 index 00000000..d6287464 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Trader.java @@ -0,0 +1,38 @@ +package cn.cunchang.stream.example; + +//交易员类 +public class Trader { + + private String name; + private String city; + + public Trader() { + } + + public Trader(String name, String city) { + this.name = name; + this.city = city; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + @Override + public String toString() { + return "Trader [name=" + name + ", city=" + city + "]"; + } + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Transaction.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Transaction.java new file mode 100644 index 00000000..1c95bbd2 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Transaction.java @@ -0,0 +1,49 @@ +package cn.cunchang.stream.example; + +//交易类 +public class Transaction { + + private Trader trader; + private Integer year; + private Integer value; + + public Transaction() { + } + + public Transaction(Trader trader, Integer year, Integer value) { + this.trader = trader; + this.year = year; + this.value = value; + } + + public Trader getTrader() { + return trader; + } + + public void setTrader(Trader trader) { + this.trader = trader; + } + + public Integer getYear() { + return year; + } + + public void setYear(Integer year) { + this.year = year; + } + + public Integer getValue() { + return value; + } + + public void setValue(Integer value) { + this.value = value; + } + + @Override + public String toString() { + return "Transaction [trader=" + trader + ", year=" + year + ", value=" + + value + "]"; + } + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/ForkJoinCalculate.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/ForkJoinCalculate.java new file mode 100644 index 00000000..25baab69 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/ForkJoinCalculate.java @@ -0,0 +1,52 @@ +package cn.cunchang.stream.parallel; + +import java.util.concurrent.RecursiveTask; + +/** + * ForkJoin采用parallel stream + * 使用ForkJoin必须继承RecursiveTask或RecursiveAction + * RecursiveTask有返回值 + * RecursiveAction没有返回值 + * @author lastwhisper + */ +public class ForkJoinCalculate extends RecursiveTask { + + /** + * + */ + private static final long serialVersionUID = 13475679780L; + private static final long THRESHOLD = 10000L; //临界值 + private long start; + private long end; + + public ForkJoinCalculate(long start, long end) { + this.start = start; + this.end = end; + } + + @Override + protected Long compute() { + long length = end - start; + + if (length <= THRESHOLD) { + long sum = 0; + for (long i = start; i <= end; i++) { + sum += i; + } + + return sum; + } else { + long middle = (start + end) / 2; + + ForkJoinCalculate left = new ForkJoinCalculate(start, middle); + left.fork(); //拆分,并将该子任务压入线程队列 + + ForkJoinCalculate right = new ForkJoinCalculate(middle + 1, end); + right.fork(); + + return left.join() + right.join(); + } + + } + +} \ No newline at end of file diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/TestForkJoin.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/TestForkJoin.java new file mode 100644 index 00000000..31bea0b1 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/TestForkJoin.java @@ -0,0 +1,49 @@ +package cn.cunchang.stream.parallel; + +import org.junit.Test; + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.stream.LongStream; + +public class TestForkJoin { + + @Test + public void test1(){ + long start = System.currentTimeMillis(); + ForkJoinPool pool = new ForkJoinPool(); + ForkJoinTask task = new ForkJoinCalculate(0L, 10000000000L); + + long sum = pool.invoke(task); + System.out.println(sum); + long end = System.currentTimeMillis(); + + System.out.println("耗费的时间为: " + (end - start)); //112-1953-1988-2654-2647-20663-113808 + } + + @Test + public void test2(){ + long start = System.currentTimeMillis(); + + long sum = 0L; + for (long i = 0L; i <= 10000000000L; i++) { + sum += i; + } + System.out.println(sum); + long end = System.currentTimeMillis(); + System.out.println("耗费的时间为: " + (end - start)); //34-3174-3132-4227-4223-31583 + } + + @Test + public void test3(){ //直接使用java8的并行流 + long start = System.currentTimeMillis(); + Long sum = LongStream.rangeClosed(0L, 10000000000L) + .parallel() + .sum(); + + System.out.println(sum); + long end = System.currentTimeMillis(); + System.out.println("耗费的时间为: " + (end - start)); //2061-2053-2086-18926 + } + +} \ No newline at end of file diff --git "a/java-basic/feature-jdk8/src/main/java/cn/cunchang/\345\217\202\350\200\203.txt" "b/java-basic/feature-jdk8/src/main/java/cn/cunchang/\345\217\202\350\200\203.txt" new file mode 100644 index 00000000..009d2b3e --- /dev/null +++ "b/java-basic/feature-jdk8/src/main/java/cn/cunchang/\345\217\202\350\200\203.txt" @@ -0,0 +1 @@ +https://blog.csdn.net/zxm1306192988/article/details/73744378 \ No newline at end of file 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 new file mode 100644 index 00000000..eb0c5343 --- /dev/null +++ b/java-basic/interview/pom.xml @@ -0,0 +1,33 @@ + + + 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/src/main/java/cn/lastwhisper/interview/AccessModifier/A1.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/A1.java new file mode 100644 index 00000000..750d638a --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/A1.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.interview.AccessModifier; + +/** + * @author lastwhisper + */ +public class A1 { + // 不使用访问修饰符 + int a; + // 不使用访问修饰符 + int sum(int m, int n) { + return m + n; + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/A2.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/A2.java new file mode 100644 index 00000000..6bf8407f --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/A2.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.interview.AccessModifier; + +/** + * @author lastwhisper + */ +public class A2 { + // protected修饰的变量——》受保护的变量 + protected int a; + // protected修饰的方法——》受保护的方法 + protected int sum(int m, int n) { + return m + n; + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/defaulttest/A.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/defaulttest/A.java new file mode 100644 index 00000000..4e08f3a9 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/defaulttest/A.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.interview.AccessModifier.defaulttest; + +/** + * @author lastwhisper + */ +public class A { + // 不使用访问修饰符 + int a; + // 不使用访问修饰符 + int sum(int m, int n) { + return m + n; + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/defaulttest/B.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/defaulttest/B.java new file mode 100644 index 00000000..a1f67c15 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/defaulttest/B.java @@ -0,0 +1,15 @@ +package cn.lastwhisper.interview.AccessModifier.defaulttest; + +//import cn.lastwhisper.A1; + +/** + * @author lastwhisper + */ +public class B { + public static void main(String[] args) { + //A1 aObject = new A1(); + A aObject = new A(); + // default修饰符,同包可以访问,不同包不可以访问 + aObject.a = 10; + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/privatetest/A.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/privatetest/A.java new file mode 100644 index 00000000..a447f8b3 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/privatetest/A.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.interview.AccessModifier.privatetest; + +/** + * @author lastwhisper + */ +public class A { + // private修饰的变量——》私有变量 + private int a; + // private修饰的方法——》私有方法 + private int sum(int m, int n) { + return m + n; + } + public int getA() { + return a; + } + public static void main(String[] args) { + A aObject = new A(); + System.out.println(aObject.a); + } + +} + + diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/privatetest/B.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/privatetest/B.java new file mode 100644 index 00000000..b1c5104a --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/privatetest/B.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.interview.AccessModifier.privatetest; + +/** + * @author lastwhisper + */ +public class B { + public static void main(String[] args) { + A aObject = new A(); + // private访问修饰,脱离类无法访问 + //System.out.println(aObject.a); + System.out.println(aObject.getA()); + + B b = new B(); + C c = b.new C(); + + } + + private class C{ + + private class D{ + + } + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/protectedtest/A.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/protectedtest/A.java new file mode 100644 index 00000000..23212b2e --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/protectedtest/A.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.interview.AccessModifier.protectedtest; + +/** + * @author lastwhisper + */ +public class A { + // protected修饰的变量——》受保护的变量 + protected int a; + // protected修饰的方法——》受保护的方法 + protected int sum(int m, int n) { + return m + n; + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/protectedtest/B.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/protectedtest/B.java new file mode 100644 index 00000000..d2adf065 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/protectedtest/B.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.interview.AccessModifier.protectedtest; + +/** + * @author lastwhisper + */ +public class B { + public static void main(String[] args) { + //A2 aObject = new A2(); + A aObject = new A(); + // protected访问修饰,同包可以访问,不同包不可以访问 + aObject.a = 10; + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/publictest/A.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/publictest/A.java new file mode 100644 index 00000000..5da0631a --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/publictest/A.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.interview.AccessModifier.publictest; + +/** + * @author lastwhisper + */ +public class A { + // public修饰的变量——》公有变量 + public int a; + // public修饰的方法——》公有方法 + public int sum(int m, int n) { + return m + n; + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/publictest/B.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/publictest/B.java new file mode 100644 index 00000000..2f68b33d --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/AccessModifier/publictest/B.java @@ -0,0 +1,12 @@ +package cn.lastwhisper.interview.AccessModifier.publictest; + +/** + * @author lastwhisper + */ +public class B { + public static void main(String[] args) { + A aObject = new A(); + // public访问修饰,在任何类中都可以访问 + aObject.a = 10; + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest.java new file mode 100644 index 00000000..49ff009b --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest.java @@ -0,0 +1,137 @@ +package cn.lastwhisper.interview.ComparableAndComparator; + +import java.util.*; +import java.lang.Comparable; + +/** + * @desc "Comparator"和“Comparable”的比较程序。 + * (01) "Comparable" + * 它是一个排序接口,只包含一个函数compareTo()。 + * 一个类实现了Comparable接口,就意味着“该类本身支持排序”,它可以直接通过Arrays.sort() 或 Collections.sort()进行排序。 + * (02) "Comparator" + * 它是一个比较器接口,包括两个函数:compare() 和 equals()。 + * 一个类实现了Comparator接口,那么它就是一个“比较器”。其它的类,可以根据该比较器去排序。 + *

+ * 综上所述:Comparable是内部比较器,而Comparator是外部比较器。 + * 一个类本身实现了Comparable比较器,就意味着它本身支持排序;若它本身没实现Comparable,也可以通过外部比较器Comparator进行排序。 + */ +public class CompareComparatorAndComparableTest { + + public static void main(String[] args) { + // 新建ArrayList(动态数组) + ArrayList list = new ArrayList(); + // 添加对象到ArrayList中 + list.add(new Person("ccc", 20)); + list.add(new Person("AAA", 30)); + list.add(new Person("bbb", 10)); + list.add(new Person("ddd", 40)); + + // 打印list的原始序列 + System.out.printf("Original sort, list:%s\n", list); + + // 对list进行排序 + // 这里会根据“Person实现的Comparable接口”进行排序,即会根据“name”进行排序 + Collections.sort(list); + System.out.printf("Name sort, list:%s\n", list); + + // 通过“比较器(AscAgeComparator)”,对list进行排序 + // AscAgeComparator的排序方式是:根据“age”的升序排序 + Collections.sort(list, new AscAgeComparator()); + System.out.printf("Asc(age) sort, list:%s\n", list); + + // 通过“比较器(DescAgeComparator)”,对list进行排序 + // DescAgeComparator的排序方式是:根据“age”的降序排序 + Collections.sort(list, new DescAgeComparator()); + System.out.printf("Desc(age) sort, list:%s\n", list); + + // 判断两个person是否相等 + testEquals(); + } + + /** + * @desc 测试两个Person比较是否相等。 + * 由于Person实现了equals()函数:若两person的age、name都相等,则认为这两个person相等。 + * 所以,这里的p1和p2相等。 + *

+ * TODO:若去掉Person中的equals()函数,则p1不等于p2 + */ + private static void testEquals() { + Person p1 = new Person("eee", 100); + Person p2 = new Person("eee", 100); + if (p1.equals(p2)) { + System.out.printf("%s EQUAL %s\n", p1, p2); + } else { + System.out.printf("%s NOT EQUAL %s\n", p1, p2); + } + } + + /** + * @desc Person类。 + * Person实现了Comparable接口,这意味着Person本身支持排序 + */ + private static class Person implements Comparable { + int age; + String name; + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + public String toString() { + return name + " - " + age; + } + + /** + * 比较两个Person是否相等:若它们的name和age都相等,则认为它们相等 + */ + boolean equals(Person person) { + if (this.age == person.age && this.name == person.name) + return true; + return false; + } + + /** + * @desc 实现 “Comparable” 的接口,即重写compareTo函数。 + * 这里是通过“person的名字”进行比较的 + */ + @Override + public int compareTo(Person person) { + return name.compareTo(person.name); + //return this.name - person.name; + } + } + + /** + * @desc AscAgeComparator比较器 + * 它是“Person的age的升序比较器” + */ + private static class AscAgeComparator implements Comparator { + + @Override + public int compare(Person p1, Person p2) { + return p1.getAge() - p2.getAge(); + } + } + + /** + * @desc DescAgeComparator比较器 + * 它是“Person的age的升序比较器” + */ + private static class DescAgeComparator implements Comparator { + + @Override + public int compare(Person p1, Person p2) { + return p2.getAge() - p1.getAge(); + } + } + +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest1.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest1.java new file mode 100644 index 00000000..cc2412a5 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest1.java @@ -0,0 +1,77 @@ +package cn.lastwhisper.interview.EqualsAndhashCode; + +import java.util.HashSet; + +/** + * @author gaojun + * @desc 比较equals() 返回true 以及 返回false时, hashCode()的值。 + * @email 15037584397@163.com + */ +public class ConflictHashCodeTest1 { + + public static void main(String[] args) { + // 新建Person对象 + Person p1 = new Person("tom", 25); + Person p2 = new Person("tom", 25); + Person p3 = new Person("tom", 25); + // 新建HashSet对象 + + HashSet set = new HashSet(); + set.add(p1); + set.add(p2); + set.add(p3); + + // 比较p1 和 p2, 并打印它们的hashCode() + System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode()); + // 打印set + System.out.printf("set:%s\n", set); + } + + /** + * @author gaojun + * @desc Person类 + */ + private static class Person { + + String name; + int age; + + public Person(String name, int age) { + this.age = age; + this.name = name; + } + + @Override + public String toString() { + return "Person{" + + "age=" + age + + ", name='" + name + '\'' + + '}'; + } + + /** + * @desc 重写equals方法 + * @author gaojun + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + // 如果是同一个对象返回true,反之返回false + if (this == obj) { + return true; + } + // 判断类型是否相同 + if (this.getClass() != obj.getClass()) { + return false; + } + Person person = (Person) obj; + if (name.equals(person.name) && age == person.age) { + return true; + } else { + return false; + } + } + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest2.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest2.java new file mode 100644 index 00000000..22593fdc --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest2.java @@ -0,0 +1,90 @@ +package cn.lastwhisper.interview.EqualsAndhashCode; + +import java.util.HashSet; + +/** + * @author gaojun + * @desc 比较equals() 返回true 以及 返回false时, hashCode()的值。 + * @email 15037584397@163.com + */ +public class ConflictHashCodeTest2 { + + public static void main(String[] args) { + // 新建Person对象 + Person p1 = new Person("tom", 25); + Person p2 = new Person("tom", 25); + Person p3 = new Person("luck", 30); + Person p4 = new Person("TOM", 25); + // 新建HashSet对象 + + HashSet set = new HashSet(); + set.add(p1); + set.add(p2); + set.add(p3); + + // 比较p1 和 p2, 并打印它们的hashCode() + System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode()); + // 比较p1 和 p4, 并打印它们的hashCode() + System.out.printf("p1.equals(p4) : %s; p1(%d) p4(%d)\n", p1.equals(p4), p1.hashCode(), p4.hashCode()); + // 打印set + System.out.printf("set:%s\n", set); + } + + /** + * @author gaojun + * @desc Person类 + */ + private static class Person { + + String name; + int age; + + public Person(String name, int age) { + this.age = age; + this.name = name; + } + + @Override + public String toString() { + return "Person{" + + "age=" + age + + ", name='" + name + '\'' + + '}'; + } + + /** + * @desc 重写hsahcode方法 + * @author gaojun + */ + @Override + public int hashCode() { + int namehash = name.toUpperCase().hashCode(); + return namehash ^ age; + } + + /** + * @desc 重写equals方法 + * @author gaojun + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + // 如果是同一个对象返回true,反之返回false + if (this == obj) { + return true; + } + // 判断类型是否相同 + if (this.getClass() != obj.getClass()) { + return false; + } + Person person = (Person) obj; + if (name.equals(person.name) && age == person.age) { + return true; + } else { + return false; + } + } + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest1.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest1.java new file mode 100644 index 00000000..a73e061a --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest1.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.interview.EqualsAndhashCode; + +/** + * @author eval + * @description + * @email 15037584397@163.com + */ +public class EqualsTest1 { + public static void main(String[] args) { + // 新建2个相同内容的Person对象,使用默认equals比较 + Person p1 = new Person("tom", 25); + Person p2 = new Person("tom", 25); + System.out.printf("%s\n", p1.equals(p2)); + } + + /** + * @author gaojun + * @desc Person类 + */ + private static class Person { + + String name; + int age; + + public Person(String name, int age) { + this.age = age; + this.name = name; + } + + @Override + public String toString() { + return "Person{" + + "age=" + age + + ", name='" + name + '\'' + + '}'; + } + } + +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest2.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest2.java new file mode 100644 index 00000000..c168e928 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest2.java @@ -0,0 +1,65 @@ +package cn.lastwhisper.interview.EqualsAndhashCode; + +/** + * @author gaojun + * @desc 重写equals方法 + * @email 15037584397@163.com + */ +public class EqualsTest2 { + public static void main(String[] args) { + // 新建2个相同内容的Person对象,使用默认equals比较 + Person p1 = new Person("tom", 25); + Person p2 = new Person("tom", 25); + System.out.printf("%s\n", p1.equals(p2)); + } + + /** + * @author gaojun + * @desc Person类 + */ + private static class Person { + + String name; + int age; + + public Person(String name, int age) { + this.age = age; + this.name = name; + } + + @Override + public String toString() { + return "Person{" + + "age=" + age + + ", name='" + name + '\'' + + '}'; + } + + /** + * @desc 重写equals方法 + * @author gaojun + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + // 如果是同一个对象返回true,反之返回false + if (this == obj) { + return true; + } + // 判断类型是否相同 + if (this.getClass() != obj.getClass()) { + return false; + } + Person person = (Person) obj; + if (name.equals(person.name) && age == person.age) { + return true; + } else { + return false; + } + } + } + + +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest3.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest3.java new file mode 100644 index 00000000..a78b65b0 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest3.java @@ -0,0 +1,65 @@ +package cn.lastwhisper.interview.EqualsAndhashCode; + +/** + * @author gaojun + * @desc + * @email 15037584397@163.com + */ +public class EqualsTest3 { + public static void main(String[] args) { + // 新建2个相同内容的Person对象,使用默认equals比较 + Person p1 = new Person("tom", 25); + Person p2 = new Person("tom", 25); + System.out.printf("p1.equals(p2) : %s\n", p1.equals(p2)); + System.out.printf("p1==p2 : %s\n", p1 == p2); + } + + /** + * @author gaojun + * @desc Person类 + */ + private static class Person { + + String name; + int age; + + public Person(String name, int age) { + this.age = age; + this.name = name; + } + + @Override + public String toString() { + return "Person{" + + "age=" + age + + ", name='" + name + '\'' + + '}'; + } + + /** + * @desc 重写equals方法 + * @author gaojun + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + // 如果是同一个对象返回true,反之返回false + if (this == obj) { + return true; + } + // 判断类型是否相同 + if (this.getClass() != obj.getClass()) { + return false; + } + Person person = (Person) obj; + if (name.equals(person.name) && age == person.age) { + return true; + } else { + return false; + } + } + } + +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/NormalHashCodeTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/NormalHashCodeTest.java new file mode 100644 index 00000000..f123527d --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/EqualsAndhashCode/NormalHashCodeTest.java @@ -0,0 +1,58 @@ +package cn.lastwhisper.interview.EqualsAndhashCode; + +/** + * @author gaojun + * @desc 比较equals() 返回true 以及 返回false时, hashCode()的值。 + * @email 15037584397@163.com + */ +public class NormalHashCodeTest { + + public static void main(String[] args) { + // 新建2个相同内容的Person对象, + // 再用equals比较它们是否相等 + Person p1 = new Person("tom", 25); + Person p2 = new Person("tom", 25); + Person p3 = new Person("tom", 25); + System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode()); + System.out.printf("p1.equals(p3) : %s; p1(%d) p3(%d)\n", p1.equals(p3), p1.hashCode(), p3.hashCode()); + } + + /** + * @desc Person类。 + */ + private static class Person { + int age; + String name; + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public String toString() { + return name + " - " + age; + } + + /** + * @desc 覆盖equals方法 + */ + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + //如果是同一个对象返回true,反之返回false + if (this == obj) { + return true; + } + + //判断是否类型相同 + if (this.getClass() != obj.getClass()) { + return false; + } + + Person person = (Person) obj; + return name.equals(person.name) && age == person.age; + } + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/FinallyReturnTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/FinallyReturnTest.java new file mode 100644 index 00000000..e5e2035d --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/FinallyReturnTest.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.interview.Exception; + +/** + * finally中return + * @author lastwhisper + */ +public class FinallyReturnTest { + public static int finallyreturn(int n) { + try { + int r = n * n; + return r; + } finally { + if (n == 2) return 0; + } + } + + public static void main(String[] args) { + int f = finallyreturn(2); + System.out.println(f); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/FinallyTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/FinallyTest.java new file mode 100644 index 00000000..907602f2 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/FinallyTest.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.interview.Exception; +/** + * finally基础用法 + * @author lastwhisper + */ +public class FinallyTest { + + public static void main(String[] args) { + try { + int i = 10 / 0; + System.out.println("i=" + i); + } catch (ArithmeticException e) { + System.out.println("Caught Exception"); + System.out.println("e.getMessage(): " + e.getMessage()); + System.out.println("e.toString(): " + e.toString()); + System.out.println("e.printStackTrace():"); + e.printStackTrace(); + } finally { + System.out.println("run finally"); + } + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/ThrowsAndThrowTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/ThrowsAndThrowTest.java new file mode 100644 index 00000000..0ced7745 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/ThrowsAndThrowTest.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.interview.Exception; + +/** + * throws和throw的基本用法以及自定义异常 + * @author lastwhisper + */ +public class ThrowsAndThrowTest { + + public static void main(String[] args) { + try { + test(); + } catch (MyException e) { + System.out.println("Catch My Exception"); + e.printStackTrace(); + } + } + + public static void test() throws MyException { + try { + int i = 10 / 0; + System.out.println("i=" + i); + } catch (ArithmeticException e) { + throw new MyException("This is MyException,OuterClassExample() exception"); + } + } +} + +class MyException extends Exception { + public MyException() { + } + + public MyException(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/TryCatchTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/TryCatchTest.java new file mode 100644 index 00000000..43eebd6b --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/TryCatchTest.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.interview.Exception; + +/** + * try/catch基础用法 + * @author lastwhisper + */ +public class TryCatchTest { + + public static void main(String[] args) { + try { + int i = 10 / 0; + System.out.println("i=" + i); + } catch (ArithmeticException e) { + System.out.println("Caught Exception"); + System.out.println("e.getMessage(): " + e.getMessage()); + System.out.println("e.toString(): " + e.toString()); + System.out.println("e.printStackTrace():"); + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/TryTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/TryTest.java new file mode 100644 index 00000000..ccd79d0f --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Exception/TryTest.java @@ -0,0 +1,48 @@ +package cn.lastwhisper.interview.Exception; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +/** + * @author lastwhisper + */ +public class TryTest { + public void test(){ + try (FileInputStream fis = new FileInputStream("d:/59035.zip")){ + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + // 反编译后 + public void test1() + { + try + { + FileInputStream fileinputstream = new FileInputStream("d:/59035.zip"); + Throwable throwable = null; + if(fileinputstream != null) + if(throwable != null) + try + { + fileinputstream.close(); + } + catch(Throwable throwable1) + { + throwable.addSuppressed(throwable1); + } + else + fileinputstream.close(); + } + catch(FileNotFoundException filenotfoundexception) + { + filenotfoundexception.printStackTrace(); + } + catch(IOException ioexception) + { + ioexception.printStackTrace(); + } + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/Static/OuterClass.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/Static/OuterClass.java new file mode 100644 index 00000000..4ac24f32 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/Static/OuterClass.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.interview.InnerClass.Static; + +/** + * 成员内部类实例 + * @author lastwhisper + */ +public class OuterClass { + private static String name="静态内部类"; + + // 静态内部类,类比类的静态变量 + private static class InnerClass { + public void print() { + System.out.println(name+"~类比类的的静态变量"); + } + } + + public static void main(String[] args) { + OuterClass.InnerClass sample = new OuterClass.InnerClass(); + sample.print(); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/Static/Outter.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/Static/Outter.java new file mode 100644 index 00000000..a62494fd --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/Static/Outter.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.interview.InnerClass.Static; + +public class Outter { + private static int b = 2; + private int a = 1; + + protected static class Inner { + public Inner() { + //System.out.println(a);//成员变量 会报错“Non-static field 'a' cannot be referenced from a static context” + System.out.println(b);//static变量 + //print();//成员函数 会报错“Non-static field 'a' cannot be referenced from a static context” + staticPrint();//static函数 + } + } + + private void print() { + } + + private static void staticPrint() { + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/FinalTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/FinalTest.java new file mode 100644 index 00000000..219cc3ec --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/FinalTest.java @@ -0,0 +1,16 @@ +package cn.lastwhisper.interview.InnerClass.anonymous; + +public class FinalTest { + public void test(final int b) { + final int a = 100; + new Thread() { + public void run() { + //a = a + 1; + System.out.println(a); + System.out.println(b); + } + }.start(); + // 做一些耗时的操作,run()方法先执行完 + // 使用a,a变成101,本来要使用a=100的 + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/InnerClass.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/InnerClass.java new file mode 100644 index 00000000..4658e235 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/InnerClass.java @@ -0,0 +1,6 @@ +package cn.lastwhisper.interview.InnerClass.anonymous; + +public interface InnerClass { + // 接口方法默认public + void print(); +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/OuterClass.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/OuterClass.java new file mode 100644 index 00000000..a995ecf1 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/OuterClass.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.interview.InnerClass.anonymous; + + +/** + * 匿名内部类实例 + * @author lastwhisper + */ +public class OuterClass { + public static void print(InnerClass innerClass) { + innerClass.print(); + } + + public static void main(String[] args) { + OuterClass.print(new InnerClass() { + @Override + public void print() { + System.out.println("匿名内部类~由于没有引用,每次新创建的,在Minor GC时被清除"); + } + }); + //OuterClass.print(() -> System.out.println("匿名内部类~由于没有引用,每次新创建的,在Minor GC时被清除")); + } +} + + diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/OuterClassExample.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/OuterClassExample.java new file mode 100644 index 00000000..32a3c634 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/anonymous/OuterClassExample.java @@ -0,0 +1,34 @@ +package cn.lastwhisper.interview.InnerClass.anonymous; + +import javax.swing.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +public class OuterClassExample extends JFrame{ + JPasswordField passwordField; + JTextField textField; + OuterClassExample(){ + super(); + + setTitle("QQ"); + setBounds(100, 100, 380, 280); + getContentPane().setLayout(null); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + textField = new JTextField("密码"); + textField.setBounds(100, 155, 120, 21); + getContentPane().add(textField); + textField.addMouseListener(new MouseAdapter(){ + @Override + public void mouseClicked(MouseEvent e) { + getContentPane().remove(textField); + passwordField = new JPasswordField(); + passwordField.setBounds(100, 155, 120, 21); + getContentPane().add(passwordField); + } + }); + + } + public static void main(String[] args) { + new OuterClassExample().setVisible(true);; + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/local/OuterClass.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/local/OuterClass.java new file mode 100644 index 00000000..994e4a6b --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/local/OuterClass.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.interview.InnerClass.local; + +/** + * 局部内部类实例 + * @author lastwhisper + */ +public class OuterClass { + + private static int a = 1; + private String name; + + public OuterClass(String name) { + this.name = name; + } + + public void helloInnerClass() { + System.out.println("我是外部类的helloInnerClass方法,内部类你可以调用我"); + } + + public void print(int price) { + // 局部内部类,类比方法内的局部变量 + // 生命周期:局部内部类在一次方法调用之后就结束。 + class InnerClass { + int innerPrice; + + public InnerClass(int innerPrice) { + System.out.println("局部内部类~类比方法内的局部变量"); + this.innerPrice = innerPrice; + } + + public void sell() { + helloInnerClass(); + System.out.println("出售:" + name + " 单价:" + innerPrice); + } + } + InnerClass apple = new InnerClass(price); + apple.sell(); + } + + public static void main(String[] args) { + OuterClass outerClass = new OuterClass("苹果"); + outerClass.print(10); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/local/Outter.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/local/Outter.java new file mode 100644 index 00000000..6fe03b78 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/local/Outter.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.interview.InnerClass.local; + +public class Outter { + private static int b = 2; + private int a = 1; + + private void test() { + class Inner { + public Inner() { + System.out.println(a);//成员变量 + System.out.println(b);//static变量 + print();//成员函数 + staticPrint();//static函数 + } + } + } + + private void print() { + } + + private static void staticPrint() { + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/member/OuterClass.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/member/OuterClass.java new file mode 100644 index 00000000..3d0132d3 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/member/OuterClass.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.interview.InnerClass.member; + +/** + * 成员内部类实例 + * @author lastwhisper + */ +public class OuterClass { + private String name; + + public OuterClass(String name) { + this.name = name; + } + + // 成员内部类,类比对象的成员变量 + private class InnerClass{ + int innerPrice; + + public InnerClass(int innerPrice) { + System.out.println("成员内部类~类比对象的成员变量"); + this.innerPrice = innerPrice; + } + + public void print() { + helloInnerClass(); + System.out.println("出售:" + name + " 单价:" + innerPrice); + } + } + + public void helloInnerClass() { + System.out.println("我是外部类的helloInnerClass方法,内部类你可以调用我"); + } + + public static void main(String[] args) { + OuterClass sample = new OuterClass("香蕉"); + InnerClass inner = sample.new InnerClass(20); + inner.print(); + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/member/Outter.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/member/Outter.java new file mode 100644 index 00000000..6e97b919 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/InnerClass/member/Outter.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.interview.InnerClass.member; + +public class Outter { + private static int b = 2; + private int a = 1; + + protected class Inner { + public Inner() { + System.out.println(a);//成员变量 + System.out.println(b);//static变量 + print();//成员函数 + staticPrint();//static函数 + } + } + private void print() { + } + + private static void staticPrint() { + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/IterableAndIterator/IterableAndIterator.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/IterableAndIterator/IterableAndIterator.java new file mode 100644 index 00000000..04b9e28d --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/IterableAndIterator/IterableAndIterator.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.interview.IterableAndIterator; + +import java.util.Iterator; + +/** + * @author lastwhisper + */ +public class IterableAndIterator { + public static void main(String[] args) { + ResizingArrayStack stack = new ResizingArrayStack(100); + stack.push("1"); + stack.push("2"); + stack.push("3"); + // foreach + for (String s : stack) { + System.out.printf("%s ", s); + } + // iterator + //Iterator iterator = stack.iterator(); + //while (iterator.hasNext()){ + // String temp = iterator.next(); + // System.out.printf("%s ",temp); + //} + String s; + for (Iterator iterator = stack.iterator(); iterator.hasNext(); + System.out.printf("%s ", new Object[]{s})) + s = (String) iterator.next(); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack.java new file mode 100644 index 00000000..3b0235bf --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack.java @@ -0,0 +1,80 @@ +package cn.lastwhisper.interview.IterableAndIterator; + +import java.util.Iterator; + +/** + * Resizing array stack + * @author lastwhisper + */ +public class ResizingArrayStack implements Iterable { + private Item[] a;// stack entries + private int N;// size + + // Create a empty stack of size cap. + public ResizingArrayStack(int cap) { + a = (Item[]) new Object[cap]; + } + + // Add a item. + public void push(Item item) { + if (N == a.length) { + resize(2 * a.length); + } + a[N++] = item; + } + + // Delete recently added item. + public Item pop() { + Item item = a[--N]; + a[N] = null; + if (N > 0 && N == a.length / 4) { + resize(a.length / 2); + } + return item; + } + + // Is the stack empty? + public boolean isEmpty() { + return N == 0; + } + + // The numebr of items int the stack + public int size() { + return N; + } + + private void resize(int max) { + // Move the stack of size N<=max to a new array of size max. + Item[] temp = (Item[]) new Object[max]; + for (int i = 0; i < temp.length; i++) { + temp[i] = a[i]; + } + a = temp; + } + + @Override + public Iterator iterator() { + return new ReverseArrayIterator(); + } + + private class ReverseArrayIterator implements Iterator { + + private int i = N; + + @Override + public boolean hasNext() { + return i > 0; + } + + @Override + public Item next() { + return a[--i]; + } + + @Override + public void remove() { + + } + } + +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/Division.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/Division.java new file mode 100644 index 00000000..b1c06889 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/Division.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.interview.Operator; + +/** + * @author lastwhisper + */ +public class Division { + public static void main(String[] args) { + int start = 1, end = Integer.MAX_VALUE; + //System.out.println(Integer.MAX_VALUE); + System.out.println((end + start) / 2); // 溢出 + System.out.println(start + (end - start) / 2); + System.out.println(start + ((end - start) >> 1)); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/LogicalBitOperation.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/LogicalBitOperation.java new file mode 100644 index 00000000..b554872c --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/LogicalBitOperation.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.interview.Operator; + +/** + * 逻辑位运算符 + * @author lastwhisper + */ +public class LogicalBitOperation { + public static void main(String[] args) { + int a = 5 & -4;// 4 + int b = 3 | 6;// 7 + int c = 10 ^ 3;// 9 + int d = ~(-14);// 13 + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/LogicalOperator.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/LogicalOperator.java new file mode 100644 index 00000000..ca77a3d2 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/LogicalOperator.java @@ -0,0 +1,49 @@ +package cn.lastwhisper.interview.Operator; + +/** + * 逻辑运算符 + * @author lastwhisper + */ +public class LogicalOperator { + public static void main(String[] args) { + // 1. "!"表示非,对逻辑表达式进行取反运算 + System.out.println(!true);//false + System.out.println(!false);//true + + // 2. "^"表示异或,逻辑表达式相同为false,逻辑表达式不相同为true + System.out.println(true ^ true);//false + System.out.println(true ^ false);//true + System.out.println(false ^ true);//true + System.out.println(false ^ false);//false + + // 3. "&&"和"&"表示与,逻辑表达式相同为true,逻辑表达式不相同为false;其中"&&"为短路运算符。 + System.out.println(true && true);//true + System.out.println(true && false);//false + // "&&"为短路运算符,只有左侧逻辑表达式为true时,才会运算右侧逻辑表达式。 + // 与运算,左侧为false时,其实并不用继续往下运算了。 + System.out.println(false && true);//false + System.out.println(false && false);//false + System.out.println(true & true);//true + System.out.println(true & false);//false + // "&"为非短路运算符,无论左侧逻辑表达式为true或false,都要运算右侧逻辑表达式。 + // 与运算,左侧为false时,其实并不用继续往下运算了。 + System.out.println(false & true);//false + System.out.println(false & false);//false + + // 4. "||"和"|"表示或,运算符两侧逻辑表达式同时为false时,运算结果为false;其中"||"为短路运算符。 + System.out.println(true || true);// true + System.out.println(true || false);// true + // "||"为短路运算符,只有在其左侧为false时,才运算其右侧的逻辑表达式。 + // 或运算,左侧为true时,其实并不用继续往下运算了。 + System.out.println(false || true);// true + System.out.println(false || false);// false + System.out.println(true | true);// true + System.out.println(true | false);// true + // "|"为非短路运算符,无论左侧逻辑表达式为true或false,都要运算右侧逻辑表达式。 + // 或运算,左侧为true时,其实并不用继续往下运算了。 + System.out.println(false | true);// true + System.out.println(false | false);// false + + + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/ShiftOperator.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/ShiftOperator.java new file mode 100644 index 00000000..018e3941 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Operator/ShiftOperator.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.interview.Operator; + +/** + * 移位运算符 + * @author lastwhisper + */ +public class ShiftOperator { + public static void main(String[] args) { + int a = -2 << 3;// -16 + int b = 15 >> 2;// 3 + int c = -4 >> 2;// -1 + int d = 4 >>> 2;// 1 + int e = -5 >>> 1;// 2147483645 + System.out.println(15 >> 1);//7 + System.out.println(14 >> 1);//7 + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/OverloadVsOverride/OverLoadClass.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/OverloadVsOverride/OverLoadClass.java new file mode 100644 index 00000000..0c04b172 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/OverloadVsOverride/OverLoadClass.java @@ -0,0 +1,43 @@ +package cn.lastwhisper.interview.OverloadVsOverride; + +/** + * 测试重载 + * @author lastwhisper + */ +public class OverLoadClass { + + public void overloadFun() { + // 无参函数 + } + + public void overloadFun(Long id) { + // 重载overloadFun,参数个数不同 + } + + public void overloadFun(Integer id) { + // 重载overloadFun,参数类型不同 + } + + public void overloadFun(Long id, String name) { + // 重载overloadFun,参数个数不同 + } + + public void overloadFun(String name, Long id) { + // 重载overloadFun,参数顺序不同 + } + + //// 抛出异常不同,并不能构成函数重载 + //public void overloadFun() throws Exception{ + //} + // + //// 访问修饰符不同,并不能构成函数重载 + //private void overloadFun(Integer id) { + //} + // + //// 返回值不同,并不能构成函数重载 + //public int overloadFun(){ + // return 0; + //} + +} + diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/OverloadVsOverride/SubClass.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/OverloadVsOverride/SubClass.java new file mode 100644 index 00000000..b4a46a49 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/OverloadVsOverride/SubClass.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.interview.OverloadVsOverride; + +/** + * 子类 + * @author lastwhisper + */ +public class SubClass extends SuperClass { + + @Override + protected int overrideFun(int a, int b) {// private throws Exception + if (b == 0) { + return Integer.MAX_VALUE; + } + return a / b; + } + + public static void main(String[] args) { + + SuperClass superClass = new SuperClass(); + System.out.println("父类 " + superClass.overrideFun(5, 0)); + + superClass = new SubClass(); + System.out.println("子类 " + superClass.overrideFun(5, 6)); + } + +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/OverloadVsOverride/SuperClass.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/OverloadVsOverride/SuperClass.java new file mode 100644 index 00000000..36632558 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/OverloadVsOverride/SuperClass.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.interview.OverloadVsOverride; + +/** + * 父类 + * @author lastwhisper + */ +public class SuperClass { + protected int overrideFun(int a, int b) throws ArithmeticException { + int divisor = a / b; + return divisor; + } +} + diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/SwapTwoInteger/Swap1.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/SwapTwoInteger/Swap1.java new file mode 100644 index 00000000..b20576c3 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/SwapTwoInteger/Swap1.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.interview.SwapTwoInteger; + +/**@desc 错误版本 + * @author eval + */ +public class Swap1 { + + /** + * 第一步 + * 交换两个integer类型的变量 + */ + public static void swap(Integer value1, Integer value2) { + //第二步定义临时变量tempt,将value1赋值给tempt + Integer tempt = value1; + //第三步 将value2赋值value1变量 + value1 = value2; + //第四步 将tempt赋值给value2 + value2 = tempt; + + } + + public static void main(String[] args) { + + Integer firstValue = 50; + Integer anotherValue = 100; + System.out.println("交换前:firstValue=" + firstValue + " anotherValue=" + anotherValue); + swap(firstValue, anotherValue); + System.out.println("交换后:firstValue=" + firstValue + " anotherValue=" + anotherValue); + + } + +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/SwapTwoInteger/Swap2.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/SwapTwoInteger/Swap2.java new file mode 100644 index 00000000..9652ba28 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/SwapTwoInteger/Swap2.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.interview.SwapTwoInteger; + +import java.lang.reflect.Field; + +public class Swap2 { + + public static void swap(Integer value1, Integer value2) throws Exception { + + // 反射获取value属性对象 + Field declaredField = Integer.class.getDeclaredField("value"); + declaredField.setAccessible(true); + // 一定不能这么写(对于-128~127内的整数是从缓存中取的) + // Integer val = value1.intValue(); + // 不从缓存中取,在堆上新创建。 + Integer val = new Integer(value1.intValue()); + declaredField.set(value1, value2); + declaredField.set(value2, val); + } + + public static void main(String[] args) throws Exception { + + Integer firstValue = 50; + Integer anotherValue = 100; + System.out.println("交换前:firstValue=" + firstValue + " anotherValue=" + anotherValue); + swap(firstValue, anotherValue); + System.out.println("交换后:firstValue=" + firstValue + " anotherValue=" + anotherValue); + + } + +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/CycleWait.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/CycleWait.java new file mode 100644 index 00000000..98eaa748 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/CycleWait.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.interview.Thread; + +/** + * 处理线程的返回值:主线程等待法 + * @author lastwhisper + */ +public class CycleWait implements Runnable{ + private String rtv=null; + @Override + public void run() { + //子线程执行中 + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + //拿到子线程计算的结果 + rtv=Thread.currentThread().getName()+" return value"; + } + + public static void main(String[] args) throws InterruptedException { + CycleWait cycleWait = new CycleWait(); + Thread thread = new Thread(cycleWait); + thread.start(); + // 1.主线程等待法 + // 等待子线程执行完成 + //while (cycleWait.rtv==null){ + // //时间不好确定 + // Thread.sleep(100); + //} + // 2.子线程join,主线程阻塞 + thread.join(); + System.out.println(""+cycleWait.rtv); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/FutureTaskDemo.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/FutureTaskDemo.java new file mode 100644 index 00000000..9655ea66 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/FutureTaskDemo.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.interview.Thread; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + +/** + * 处理线程的返回值: + * 通过Callable接口实现:FutureTask + * @author lastwhisper + */ +public class FutureTaskDemo { + public static void main(String[] args) throws ExecutionException, InterruptedException { + FutureTask futureTask = new FutureTask(new MyCallable()); + Thread thread = new Thread(futureTask); + thread.start(); + if (!futureTask.isDone()){ + System.out.println("task is alive"); + } + System.out.println(futureTask.get()); + System.out.println("task is dead"); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/InterruptDemo.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/InterruptDemo.java new file mode 100644 index 00000000..de553a9d --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/InterruptDemo.java @@ -0,0 +1,34 @@ +package cn.lastwhisper.interview.Thread; + +/** + * 线程中断 + * @author lastwhisper + */ +public class InterruptDemo { + public static void main(String[] args) throws InterruptedException { + Thread t1 = new Thread() { + @Override + public void run() { + while (true) { + if (Thread.currentThread().isInterrupted()) { + System.out.println("intrrupted"); + break; + } + + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + System.out.println("Interrupt When Sleep"); + // 设置中断标志 + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + Thread.yield(); + } + } + }; + t1.start(); + Thread.sleep(2000); + t1.interrupt(); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/MyCallable.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/MyCallable.java new file mode 100644 index 00000000..4096388b --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/MyCallable.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.interview.Thread; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + +/** + * 处理线程的返回值 + * @author lastwhisper + */ +public class MyCallable implements Callable { + @Override + public String call() throws Exception { + //子线程执行中 + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + //拿到子线程计算的结果 + return "task return value"; + } + +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/MyRunnable.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/MyRunnable.java new file mode 100644 index 00000000..0486cf31 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/MyRunnable.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.interview.Thread; + +/** + * 线程的实现 + * @author lastwhisper + */ +public class MyRunnable implements Runnable { + @Override + public void run() { + for (int i = 0; i < 10; i++) { + System.out.println(Thread.currentThread().getName()+":"+i); + } + } + public static void main(String[] args){ + Thread mr1 = new Thread(new MyRunnable()); + Thread mr2 = new Thread(new MyRunnable()); + Thread mr3 = new Thread(new MyRunnable()); + mr1.start(); + mr2.start(); + mr3.start(); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/MyThread.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/MyThread.java new file mode 100644 index 00000000..a7f9ec61 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/MyThread.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.interview.Thread; + +/** + * 线程的实现 + * @author lastwhisper + */ +public class MyThread extends Thread { + + @Override + public void run() { + for (int i = 0; i < 10; i++) { + System.out.println(Thread.currentThread().getName()+":"+i); + } + } + + public static void main(String[] args){ + Thread mt1 = new MyThread(); + Thread mt2 = new MyThread(); + Thread mt3 = new MyThread(); + mt1.start(); + mt2.start(); + mt3.start(); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/SyncBlockAndMethod.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/SyncBlockAndMethod.java new file mode 100644 index 00000000..0ab9c45f --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/SyncBlockAndMethod.java @@ -0,0 +1,18 @@ +package cn.lastwhisper.interview.Thread; + +public class SyncBlockAndMethod { + public void syncsTask() { + synchronized (this) { + System.out.println("Hello"); + //可重入 + synchronized (this){ + System.out.println("World"); + } + } + } + + public synchronized void syncTask() { + System.out.println("Hello Again"); + } + +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/SynchronizeDemo.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/SynchronizeDemo.java new file mode 100644 index 00000000..cf7a53d2 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/SynchronizeDemo.java @@ -0,0 +1,81 @@ +package cn.lastwhisper.interview.Thread; + +/** + * synchronize支持对象锁和字节码锁 + * + * @author lastwhisper + */ +public class SynchronizeDemo { + /** + * @param args + */ + public static void main(String[] args) { + new SynchronizeDemo().init(); + } + + private void init(){ + final Outputer outputer = new Outputer(); + new Thread(new Runnable(){ + @Override + public void run() { + while(true){ + try { + Thread.sleep(10); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + outputer.output("zhangxiaoxiang"); + } + + } + }).start(); + + new Thread(new Runnable(){ + @Override + public void run() { + while(true){ + try { + Thread.sleep(10); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + outputer.output2("lihuoming"); + } + + } + }).start(); + + } + + static class Outputer{ + + public void output(String name){ + int len = name.length(); + synchronized (Outputer.class) + { + for(int i=0;i future = cachedThreadPool.submit(new MyCallable()); + if(!future.isDone()){ + System.out.println("task is alive"); + } + try { + System.out.println(future.get()); + System.out.println("task is dead"); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + }finally { + cachedThreadPool.shutdown(); + } + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/ThreadTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/ThreadTest.java new file mode 100644 index 00000000..4b70df20 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/ThreadTest.java @@ -0,0 +1,19 @@ +package cn.lastwhisper.interview.Thread; + +/** + * 线程run方法和start方法的区别 + * @author lastwhisper + */ +public class ThreadTest { + public static void main(String[] args){ + Thread thread = new Thread(){ + @Override + public void run() { + System.out.println("current Thread name is "+Thread.currentThread().getName()); + } + }; + System.out.println("current Thread name is "+Thread.currentThread().getName()); + //Thread.run(); + thread.start(); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/VolatileDemo.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/VolatileDemo.java new file mode 100644 index 00000000..4fcdf2be --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/VolatileDemo.java @@ -0,0 +1,41 @@ +package cn.lastwhisper.interview.Thread; + +/** + * 一、volatile:当多个线程进行操作共享数据时,可以保证内存中的数据可见。 + * 相比 synchronize 是一种较为轻量级的同步策略。 + * @author lastwhisper + */ +public class VolatileDemo { + public static void main(String[] args) { + ThreadDemo td = new ThreadDemo(); + new Thread(td).start(); + while (true) { + synchronized (td){ + if (td.isFlag()) { + System.out.println("-----------------"); + break; + } + } + } + } +} + +class ThreadDemo implements Runnable { + + private boolean flag = false; + + @Override + public void run() { + try { + Thread.sleep(200); + } catch (InterruptedException e) { + e.printStackTrace(); + } + flag = true; + System.out.println("flag=" + flag); + } + + public boolean isFlag() { + return flag; + } +} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/WaitSleepDemo.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/WaitSleepDemo.java new file mode 100644 index 00000000..5c306195 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/WaitSleepDemo.java @@ -0,0 +1,55 @@ +package cn.lastwhisper.interview.Thread; + +/** + * wait和sleep的区别 + * Thread.sleep只会让出CPU,不会导致锁行为的改变 + * Object.wait不仅让出CPU,还会释放已经占有的同步资源锁 + * @author lastwhisper + */ +public class WaitSleepDemo { + + public static void main(String[] args) { + final Object lock = new Object(); + // 线程A的sleep、wait对线程B的影响 + new Thread(new Runnable() { + @Override + public void run() { + System.out.println("Thread A is waiting to get lock"); + synchronized (lock) { + try { + System.out.println("Thread A get lock"); + Thread.sleep(200); + System.out.println("Thread A do wait method"); + //lock.wait(1000); + Thread.sleep(1000); + System.out.println("Thread A is done"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }).start(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + new Thread(new Runnable() { + @Override + public void run() { + System.out.println("Thread B is waiting to get lock"); + synchronized (lock) { + try { + System.out.println("Thread B get lock"); + System.out.println("Thread B do wait method"); + //Thread.sleep(100); + lock.wait(100); + System.out.println("Thread B is done"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }).start(); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/WaitSleepDemo1.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/WaitSleepDemo1.java new file mode 100644 index 00000000..e86cdc93 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/WaitSleepDemo1.java @@ -0,0 +1,54 @@ +package cn.lastwhisper.interview.Thread; + +/** + * wait和sleep的区别 + * Thread.sleep只会让出CPU,不会导致锁行为的改变 + * Object.wait不仅让出CPU,还会释放已经占有的同步资源锁 + * @author lastwhisper + */ +public class WaitSleepDemo1 { + + public static void main(String[] args) { + final Object lock = new Object(); + // 线程A的sleep、wait对线程B的影响 + new Thread(new Runnable() { + @Override + public void run() { + System.out.println("Thread A is waiting to get lock"); + synchronized (lock) { + try { + System.out.println("Thread A get lock"); + Thread.sleep(200); + System.out.println("Thread A do wait method"); + lock.wait(); + System.out.println("Thread A is done"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }).start(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + new Thread(new Runnable() { + @Override + public void run() { + System.out.println("Thread B is waiting to get lock"); + synchronized (lock) { + try { + System.out.println("Thread B get lock"); + Thread.sleep(100); + System.out.println("Thread B do wait method"); + lock.notify(); + System.out.println("Thread B is done"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }).start(); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/YieldDemo.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/YieldDemo.java new file mode 100644 index 00000000..42803bce --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Thread/YieldDemo.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.interview.Thread; + +/** + * yield的作用 + * @author lastwhisper + */ +public class YieldDemo { + public static void main(String[] args) { + Runnable runnable = new Runnable() { + @Override + public void run() { + for (int i = 0; i < 10; i++) { + System.out.println(Thread.currentThread().getName() + i); + if (i == 5) { + Thread.yield(); + } + } + } + }; + Thread threadA = new Thread(runnable, "A"); + Thread threadB = new Thread(runnable, "B"); + threadA.start(); + threadB.start(); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example1.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example1.java new file mode 100644 index 00000000..0e9a45cc --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example1.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.interview.ValueAndaddress; + +/** + * @author gaojun + * @desc 形参为基本数据类型 + * @email 15037584397@163.com + */ +public class Example1 { + public static void main(String[] args) { + int i = 10; + + pass(i); + + System.out.println("print in main , i is " + i); + } + + public static void pass(int j) { + j = 20; + System.out.println("print in pass , j is " + j); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example2.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example2.java new file mode 100644 index 00000000..c79265fd --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example2.java @@ -0,0 +1,51 @@ +package cn.lastwhisper.interview.ValueAndaddress; + +/** + * @author gaojun + * @desc 形参为对象 + * @email 15037584397@163.com + */ +public class Example2 { + public static void main(String[] args) { + + User hollis = new User(); + hollis.setName("gaojun"); + hollis.setGender("Male"); + pass(hollis); + System.out.println("print in main , user is " + hollis); + } + + public static void pass(User user) { + user.setName("gaojun-update"); + System.out.println("print in pass , user is " + user); + } + + private static class User { + private String name; + private String gender; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + @Override + public String toString() { + return "User{" + + "name='" + name + '\'' + + ", gender='" + gender + '\'' + + '}'; + } + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example3.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example3.java new file mode 100644 index 00000000..7fb0ccdd --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example3.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.interview.ValueAndaddress; + +/** + * @author gaojun + * @desc 传递对象 + * @email 15037584397@163.com + */ +public class Example3 { + public static void main(String[] args) { + + String name = "gaojun"; + pass(name); + System.out.println("print in main , name is " + name); + } + + public static void pass(String name) { + name = "gaojun-update"; + System.out.println("print in pass , name is " + name); + } +} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example4.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example4.java new file mode 100644 index 00000000..d8bbb2b7 --- /dev/null +++ b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ValueAndaddress/Example4.java @@ -0,0 +1,53 @@ +package cn.lastwhisper.interview.ValueAndaddress; + +/** + * @author gaojun + * @desc 形参为对象 + * @email 15037584397@163.com + */ +public class Example4 { + public static void main(String[] args) { + + User hollis = new User(); + hollis.setName("gaojun"); + hollis.setGender("Male"); + pass(hollis); + System.out.println("print in main , user is " + hollis); + } + + public static void pass(User user) { + user = new User(); + user.setName("gaojun-update"); + user.setGender("Male"); + System.out.println("print in pass , user is " + user); + } + + private static class User { + private String name; + private String gender; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + @Override + public String toString() { + return "User{" + + "name='" + name + '\'' + + ", gender='" + gender + '\'' + + '}'; + } + } +} diff --git a/java-basic/interview/src/main/resources/project-parent.zip b/java-basic/interview/src/main/resources/project-parent.zip new file mode 100644 index 00000000..ef687d96 Binary files /dev/null and b/java-basic/interview/src/main/resources/project-parent.zip differ 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 new file mode 100644 index 00000000..9a5f8bec --- /dev/null +++ b/java-basic/jvm/pom.xml @@ -0,0 +1,92 @@ + + + + 4.0.0 + + cn.lastwhisper + jvm + pom + 1.0-SNAPSHOT + + jdk7-setting + + + + 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} + + + + 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/classloading/InterfaceInit.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/InterfaceInit.java new file mode 100644 index 00000000..e7fbdf6d --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/InterfaceInit.java @@ -0,0 +1,5 @@ +package cn.lastwhisper.jvm.classloading; + +public interface InterfaceInit { + public static int i = 0; +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/StaticCodeTest.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/StaticCodeTest.java new file mode 100644 index 00000000..1953e37f --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/StaticCodeTest.java @@ -0,0 +1,12 @@ +package cn.lastwhisper.jvm.classloading; + +/** + * 测试静态语句块和静态变量的顺序 + */ +public class StaticCodeTest { + static { + i = 0; + //System.out.println(i); + } + static int i = 1; +} \ No newline at end of file diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization1.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization1.java new file mode 100644 index 00000000..37fd3463 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization1.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.jvm.classloading.initiative; + +/** + * 主动引用触发初始化、演示一 + * @author lastwhisper + */ +public class Initialization1 { + // 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时, + // 如果类没有进行过初始化,则需要先触发其初始化。 + public static void main(String[] args) { + // 1.new字节码指令 + //SubClass subClass = new SubClass(); + + // 2.getstatic字节码指令 + // 被final修饰、已在编译期把结果放入常量池的静态字段除外 + int subvalue = SubClass.subvalue; + + // 3.setstatic字节码指令 + // 被final修饰、已在编译期把结果放入常量池的静态字段除外 + //SubClass.subvalue = 789; + + // 4.invokestatic字节码指令 + //SubClass.getSubvalue(); + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization2.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization2.java new file mode 100644 index 00000000..8b4f2424 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization2.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.jvm.classloading.initiative; + +import java.lang.reflect.Constructor; + +/** + * 主动引用触发初始化、演示二 + * @author lastwhisper + */ +public class Initialization2 { + public static void main(String[] args) { + // 使用java.lang.reflect包的方法对类进行反射调用的时候, + // 如果类没有进行过初始化,则需要先触发其初始化。 + + try { + // 使用Class.forName();也行,不要使用对象.class。 + Class clazz = SubClass.class; + Constructor constructor = clazz.getConstructor(); + constructor.newInstance(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization3.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization3.java new file mode 100644 index 00000000..a2910586 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization3.java @@ -0,0 +1,19 @@ +package cn.lastwhisper.jvm.classloading.initiative; + +/** + * 主动引用触发初始化、演示三 + * @author lastwhisper + */ +public class Initialization3 { + // 当初始化一个类的时候,如果发现其父类还没有进行过初始化, + // 则需要先触发其父类的初始化 + public static void main(String[] args) { + // 在Initialization1的new指令和Initialization2的反射创建对象都有体现 + SubClass subClass = new SubClass(); + //初始化顺序 + //SuperClass Static code init! 首先初始化父类静态代码块 + //SubClass Static code init! 其次初始化自己的静态代码块 + //SuperClass constructor init! 其次初始化父类的构造器 + //SubClass constructor init! 其次初始化自己的构造器 + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization4.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization4.java new file mode 100644 index 00000000..0ada7135 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization4.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.jvm.classloading.initiative; + +/** + * 主动引用触发初始化、演示四 + * @author lastwhisper + */ +public class Initialization4 { + + static { + System.out.println("Initialization4 Static code init!"); + } + + public Initialization4() { + System.out.println("Initialization4 constructor init!"); + } + + public static void main(String[] args) { + // 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。 + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization5.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization5.java new file mode 100644 index 00000000..e8567938 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/Initialization5.java @@ -0,0 +1,34 @@ +package cn.lastwhisper.jvm.classloading.initiative; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +/** + * 主动引用触发初始化、演示五 + * @author lastwhisper + */ +public class Initialization5 { + + public static void main(String[] args) { + + MethodHandles.Lookup lookup = MethodHandles.lookup(); + try { + + + // REF_invokeStatic + MethodHandle testREF_invokeStatic = lookup.findStatic(MethodHandleClass.class, "testREF_invokeStatic", MethodType.methodType(void.class, String.class)); + testREF_invokeStatic.invoke("啥也不干,打印一段话"); + + // REF_getStatic + + // REF_putStatic + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/MethodHandleClass.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/MethodHandleClass.java new file mode 100644 index 00000000..667ee36b --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/MethodHandleClass.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.jvm.classloading.initiative; + +/** + * @author lastwhisper + */ +public class MethodHandleClass { + + static { + System.out.println("MethodHandleClass Static code init!"); + } + public MethodHandleClass() { + System.out.println("MethodHandleClass constructor init!"); + } + + // REF_invokeStatic + public static void testREF_invokeStatic(String str) { + System.out.println(str); + } + +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/SubClass.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/SubClass.java new file mode 100644 index 00000000..407ee703 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/SubClass.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.jvm.classloading.initiative; + +/** + * @author lastwhisper + */ +public class SubClass extends SuperClass { + + public static int subvalue = 456; + + static { + System.out.println("SubClass Static code init!"); + } + + public SubClass() { + System.out.println("SubClass constructor init! "); + } + + public static int getSubvalue() { + return subvalue; + } + + public static void setSubvalue(int subvalue) { + SubClass.subvalue = subvalue; + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/SuperClass.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/SuperClass.java new file mode 100644 index 00000000..4ebac39b --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/initiative/SuperClass.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.jvm.classloading.initiative; + +/** + * @author lastwhisper + */ +public class SuperClass { + public static int value = 123; + + static { + System.out.println("SuperClass Static code init!"); + } + + public SuperClass() { + System.out.println("SuperClass constructor init! "); + } + + public static int getValue() { + return value; + } + + public static void setValue(int value) { + SuperClass.value = value; + } +} + diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/ConstClass.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/ConstClass.java new file mode 100644 index 00000000..a0a9d113 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/ConstClass.java @@ -0,0 +1,12 @@ +package cn.lastwhisper.jvm.classloading.passive; + +/** + * @author lastwhisper + */ +public class ConstClass { + public static final String HELLOWORLD = "hello world"; + + static { + System.out.println("ConstClass init!"); + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/Interface.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/Interface.java new file mode 100644 index 00000000..4290a194 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/Interface.java @@ -0,0 +1,6 @@ +package cn.lastwhisper.jvm.classloading.passive; + +public interface Interface { + //一个接口在初始化时,并不要求初始化其全部接口, + // 只会初始化使用到的接口时(如引用接口中定义的常量),才会初始化. +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/NotInitialization1.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/NotInitialization1.java new file mode 100644 index 00000000..212f9408 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/NotInitialization1.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.jvm.classloading.passive; + +import cn.lastwhisper.jvm.classloading.initiative.SubClass; + +/** + * 被动使用类字段不触发初始化、演示一 + * @author lastwhisper + */ +public class NotInitialization1 { + // 子类引用父类的静态字段,只会触发子类的加载、父类的初始化,不会导致子类初始化 + // 是否要触发子类的加载和验证,在虚拟机规范中并未明确规定,这点取决于虚拟机的具体实现 + // 对于Sun HotSpot虚拟机,可通过-XX:+TraceClassLoading参数观察到此操作会导致子类的加载 + public static void main(String[] args) { + System.out.println(SubClass.value); + //[Loaded cn.lastwhisper.jvm.classloading.passive.SubClass from ...] + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/NotInitialization2.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/NotInitialization2.java new file mode 100644 index 00000000..a33e3c3a --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/NotInitialization2.java @@ -0,0 +1,16 @@ +package cn.lastwhisper.jvm.classloading.passive; + +import cn.lastwhisper.jvm.classloading.initiative.SuperClass; + +/** + * 被动使用类字段不触发初始化、演示二 + * -XX:+TraceClassLoading + * @author lastwhisper + */ +public class NotInitialization2 { + public static void main(String[] args){ + // 通过数组定义来引用类,不会触发此类的初始化 + // 会触发L+全类名的初始化 + SuperClass[] superClasses = new SuperClass[10]; + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/NotInitialization3.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/NotInitialization3.java new file mode 100644 index 00000000..e0ab6a8c --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloading/passive/NotInitialization3.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.jvm.classloading.passive; + +/** + * 被动使用类字段不触发初始化、演示三 + * @author lastwhisper + */ +public class NotInitialization3 { + public static void main(String[] args) { + // 常量在编译阶段会进行常量优化,将常量存入**调用类**的常量池中, + // 本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。 + System.out.println(ConstClass.HELLOWORLD); + // hello world + } +} 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/finalize/Finalization.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/finalize/Finalization.java new file mode 100644 index 00000000..270c0665 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/finalize/Finalization.java @@ -0,0 +1,42 @@ +package cn.lastwhisper.jvm.gc.finalize; + +/** + * 1.对象可以在被GC时自救 + * 2.自救的机会只有一次 + * @author lastwhisper + */ +public class Finalization { + public static Finalization SAVE_HOOK = null; + + @Override + protected void finalize() throws Throwable { + super.finalize(); + Finalization.SAVE_HOOK = this; + System.out.println("处理系统资源、执行其他清理或者对象自救"); + } + + public static void main(String[] args) throws Exception { + SAVE_HOOK = new Finalization(); + // 在堆中无GC Roots,会被GC,但是SAVE_HOOK实现了finalize有一次自救的机会 + SAVE_HOOK = null; + //显示调用垃圾回收 + System.gc(); + // finalize方法优先级很低,暂停0.5s等待它 + Thread.sleep(500); + if (SAVE_HOOK != null) { + System.out.println("SAVE_HOOK对象还活着"); + } else { + System.out.println("SAVE_HOOK对象已经被回收"); + } + // finalize方法只会调用一次,第二次自救失败 + SAVE_HOOK = null; + System.gc(); + // finalize方法优先级很低,暂停0.5s等待它 + Thread.sleep(500); + if (SAVE_HOOK != null) { + System.out.println("SAVE_HOOK对象还活着"); + } else { + System.out.println("SAVE_HOOK对象已经被回收"); + } + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/finalize/Finalization2.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/finalize/Finalization2.java new file mode 100644 index 00000000..124d8927 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/finalize/Finalization2.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.jvm.gc.finalize; + +/** + * finalize方法的不确定性 + * @author lastwhisper + */ +public class Finalization2 { + public static Finalization2 SAVE_HOOK = null; + + @Override + protected void finalize() throws InterruptedException { + Thread.sleep(500); + System.out.println("第一个文件资源关闭。。。"); + Thread.sleep(500); + System.out.println("第二个文件资源关闭。。。"); + Thread.sleep(500); + System.out.println("第三个文件资源关闭。。。"); + Thread.sleep(500); + System.out.println("第四个文件资源关闭。。。"); + } + + public static void main(String[] args) throws Exception { + SAVE_HOOK = new Finalization2(); + System.out.println("SAVE_HOOK打开了四个文件,并且进行操作"); + SAVE_HOOK = null; + System.out.println("利用finalize特性,将SAVE_HOOK=null,关闭四个文件资源"); + System.gc(); + Thread.sleep(2000);//处理别的业务 + } +} 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/PhantomReferenceDemo.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/PhantomReferenceDemo.java new file mode 100644 index 00000000..8ddf6787 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/PhantomReferenceDemo.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.jvm.gc.reference; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; + +/** + * @author lastwhisper + */ +public class PhantomReferenceDemo { + + /** + * 虚引用 + * 虚引用用来跟踪对象被垃圾回收器回收的活动。虚引用和软引用与弱引用的区别在于虚引用必须和引用队列联合使用, + * 当虚引用被加入到引用队列的时候,说明这个对象已经被回收,可以在所引用的对象回收之后可以采取必要的行动。 + */ + public static void main(String[] args) throws InterruptedException { + Object o = new Object(); + // 必须结合引用队列 + ReferenceQueue referenceQueue = new ReferenceQueue<>(); + // 虚引用 + PhantomReference phantomReference = new PhantomReference<>(o, referenceQueue); + + System.out.println(o); + System.out.println(phantomReference.get()); + System.out.println(referenceQueue.poll()); + + System.out.println("================="); + o = null; + System.gc(); + Thread.sleep(500); + + System.out.println(o); + System.out.println(phantomReference.get()); + System.out.println(referenceQueue.poll()); + + } + +} 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 new file mode 100644 index 00000000..9b753cea --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ReferenceQueueDemo.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.jvm.gc.reference; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +/** + * 监控对象是否被收回 + */ +public class ReferenceQueueDemo { + public static void main(String[] args) throws InterruptedException{ + Object o = new Object(); + ReferenceQueue referenceQueue = new ReferenceQueue<>(); + WeakReference weakReference = new WeakReference<>(o,referenceQueue); + System.out.println(o); + System.out.println(weakReference.get()); + System.out.println(referenceQueue.poll());// o没有被回收时,队列为空 + + System.out.println("============="); + o = null; + System.gc(); + Thread.sleep(500); + + 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 new file mode 100644 index 00000000..924dbafe --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ReferenceQueueTest.java @@ -0,0 +1,48 @@ +package cn.lastwhisper.jvm.gc.reference; + +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; + +/** + * 监控对象是否被收回 + */ +public class ReferenceQueueTest { + + private static ReferenceQueue rq = new ReferenceQueue(); + private static int _1M = 1024*1024; + /** + * + * 因为map的key是WeakReference,所以在内存不足的时候,weakReference所指向的对象就会被GC, + * 在对象被GC的同时,会把该对象的包装类即weakReference放入到ReferenceQueue里面。 + * + * 但是这个map的大小是100. + * + */ + public static void main(String[] args) { + Thread thread = new Thread(() -> { + try { + int cnt = 0; + WeakReference k; + while((k = (WeakReference) rq.remove()) != null) { + System.out.println((cnt++) + " 回收了:" + k.get()); + } + } catch(InterruptedException e) { + //结束循环 + } + }); + thread.setDaemon(true); + thread.start(); + + Set handlerSet = new HashSet<>(); + for(int i = 0;i < 100;i++) { + byte[] bytes = new byte[_1M]; + WeakReference weakReference = new WeakReference<>(bytes, rq); + handlerSet.add(weakReference); + } + 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 new file mode 100644 index 00000000..746f73cd --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/SoftReferenceDemo.java @@ -0,0 +1,62 @@ +package cn.lastwhisper.jvm.gc.reference; + +import java.lang.ref.SoftReference; + + +public class SoftReferenceDemo { + + /** + * 软引用case + * 内存够用的时候就保留软引用,不够用就回收软引用 + * @author lastwhisper + */ + public static void main(String[] args) { + //softRef_Memory_Enough(); + softRef_Memory_NotEnough(); + } + + public static void softRef_Memory_Enough() { + Object o = new Object(); + SoftReference softReference = new SoftReference<>(o); + + System.out.println("---内存充足---"); + System.out.println("原引用:"+o); + System.out.println("软引用:"+softReference.get()); + + o = null; + System.gc(); + System.out.println("----原引用置为null,并开始GC---"); + System.out.println("原引用:"+o);//null + System.out.println("软引用:"+softReference.get());//java.lang.Object@4d7e1886 + } + + public static void softRef_Memory_NotEnough() { + Object o = new Object(); + SoftReference softReference = new SoftReference<>(o); + + System.out.println("---内存充足---"); + System.out.println("原引用:"+o); + System.out.println("软引用:"+softReference.get()); + + o = null; + try { + // -Xms9m -Xmx9m 新生代:老年代=1:2 3MB:6MB + // 大对象直接如老年代 + //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("原引用:"+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/gc/reference/StrongReferenceDemo.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/StrongReferenceDemo.java new file mode 100644 index 00000000..b7fd1c40 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/StrongReferenceDemo.java @@ -0,0 +1,41 @@ +package cn.lastwhisper.jvm.gc.reference; + + +public class StrongReferenceDemo { + /** + * 强引用case + * 当内存空间不足时,Java虚拟机宁愿抛出OutOfMemoryError, + * 也不会随意回收这个对象,如果不使用这个对象时,可以设置o=null。 + */ + public static void main(String[] args) { + //strongRef_Memory_Enough(); + strongRef_Memory_NotEnough(); + } + + private static void strongRef_Memory_NotEnough() { + Object o = new Object(); + System.out.println("---内存充足---"); + System.out.println("原引用:"+o); + + try { + // -Xms9m -Xmx9m 新生代:老年代=1:2 3MB:6MB + // 大对象直接如老年代 + //byte[] bytes = new byte[6*1024*1024];//6MB + byte[] bytes = new byte[7 * 1024 * 1024];//6MB OOM内存不足,回收软引用 + } catch (Throwable e) { + e.printStackTrace(); + } finally { + System.out.println("---OOM触发GC---"); + System.out.println("原引用:"+o); + } + + } + + private static void strongRef_Memory_Enough() { + Object obj1 = new Object();//这样定义默认的就是强引用 + Object obj2 = obj1;//obj2引用赋值 + obj1 = null; + System.gc(); + System.out.println(obj2); + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ThreadLocalMemoryLeak.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ThreadLocalMemoryLeak.java new file mode 100644 index 00000000..1470870d --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ThreadLocalMemoryLeak.java @@ -0,0 +1,52 @@ +package cn.lastwhisper.jvm.gc.reference; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * ThreadLocal导致内存泄漏 + * 弱引用只是解决了key的内存问题 + * @author lastwhisper + */ +public class ThreadLocalMemoryLeak { + private final static int TASK_LOOP_SIZE = 100; + /*线程池*/ + final static ThreadPoolExecutor poolExecutor = new + ThreadPoolExecutor(5,5,1, TimeUnit.SECONDS,new LinkedBlockingQueue<>()); + + static class LocalVariable{ + private byte[] a = new byte[1024*1024*5];//5MB + } + + ThreadLocal localVariableThreadLocal; + + public static void main(String[] args){ + + for (int i = 0; i < TASK_LOOP_SIZE; i++) { + poolExecutor.execute(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(500); + // 第一次,仅使用局部变量 20MB + //LocalVariable localVariable = new LocalVariable(); + // 第二次 放入ThreadLocal 350MB + // ThreadLocal弱引用导致内存泄漏 + ThreadLocalMemoryLeak oom = new ThreadLocalMemoryLeak(); + oom.localVariableThreadLocal = new ThreadLocal<>(); + oom.localVariableThreadLocal.set(new LocalVariable()); + // 第三次 remove解决内存泄漏 20MB + oom.localVariableThreadLocal.remove(); + + System.out.println("use local variable"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }); + } + + } + +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/WeakHashMapDemo.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/WeakHashMapDemo.java new file mode 100644 index 00000000..3aae739b --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/WeakHashMapDemo.java @@ -0,0 +1,48 @@ +package cn.lastwhisper.jvm.gc.reference; + +import java.util.HashMap; +import java.util.WeakHashMap; + +/** + * @author lastwhisper + */ +public class WeakHashMapDemo { + /** + * + */ + public static void main(String[] args) { + myHashMap(); + System.out.println("========"); + myWeakHashMap(); + } + + private static void myHashMap() { + HashMap map = new HashMap<>(); + Integer key = new Integer(1); + String value = "HashMap"; + + map.put(key, value); + System.out.println(map); + + key = null; + System.out.println(map); + System.gc(); + + System.out.println(map); + } + + private static void myWeakHashMap() { + WeakHashMap map = new WeakHashMap<>(); + Integer key = new Integer(2); + String value = "WeakHashMap"; + + map.put(key, value); + System.out.println(map); + + key = null; + System.out.println(map); + + System.gc(); + System.out.println(map);//null + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/WeakReferenceDemo.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/WeakReferenceDemo.java new file mode 100644 index 00000000..ca9f5e20 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/WeakReferenceDemo.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.jvm.gc.reference; + +import java.lang.ref.WeakReference; + + +public class WeakReferenceDemo { + /** + * 弱引用case + * 当发生GC工作时,无论当前内存是否够用,都会立即清除弱引用对象。 + */ + public static void main(String[] args) { + Object o = new Object(); + WeakReference weakReference = new WeakReference<>(o); + System.out.println("---内存充足---"); + System.out.println("原引用:"+o); + System.out.println("弱引用:"+weakReference.get()); + + o = null; + System.gc(); + System.out.println("----原引用置为null,并开始GC---"); + + System.out.println("原引用:"+o); + System.out.println("弱引用:"+weakReference.get()); + } + +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/ByteCodeSample.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/ByteCodeSample.java new file mode 100644 index 00000000..eed383ac --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/ByteCodeSample.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.jvm.memorystruct; + +/** + * 虚拟机栈中的局部变量表和操作数栈 + * @author lastwhisper + */ +public class ByteCodeSample { + public static int add(int a, int b) { + int c = 0; + c = a + b; + return c; + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/DirectMemoryOOM.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/DirectMemoryOOM.java new file mode 100644 index 00000000..3af92063 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/DirectMemoryOOM.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.jvm.memorystruct; + +//import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +/** + * VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M + * @author zzm + */ +public class DirectMemoryOOM { + + private static final int _1MB = 1024 * 1024; + + public static void main(String[] args) throws Exception { + //Field unsafeField = Unsafe.class.getDeclaredFields()[0]; + //unsafeField.setAccessible(true); + //Unsafe unsafe = (Unsafe) unsafeField.get(null); + //while (true) { + // unsafe.allocateMemory(_1MB); + //} + } +} \ No newline at end of file diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/HeapOOM.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/HeapOOM.java new file mode 100644 index 00000000..3df60426 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/HeapOOM.java @@ -0,0 +1,34 @@ +package cn.lastwhisper.jvm.memorystruct; + +import java.util.ArrayList; +import java.util.List; + +/** + * 测试堆溢出 + * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError + * @author lastwhisper + */ +public class HeapOOM { + static class OOMObject { + } + + public static void main(String[] args) { + List list = new ArrayList(); + while (true) { + list.add(new OOMObject()); + } + } +} +/** + * java.lang.OutOfMemoryError: Java heap space + * Dumping heap to java_pid16312.hprof ... + * Heap dump file created [29573180 bytes in 0.111 secs] + * Exception in Thread "main" java.lang.OutOfMemoryError: Java heap space + * at java.base/java.util.Arrays.copyOf(Arrays.java:3720) + * at java.base/java.util.Arrays.copyOf(Arrays.java:3689) + * at java.base/java.util.ArrayList.grow(ArrayList.java:237) + * at java.base/java.util.ArrayList.grow(ArrayList.java:242) + * at java.base/java.util.ArrayList.add(ArrayList.java:485) + * at java.base/java.util.ArrayList.add(ArrayList.java:498) + * at cn.lastwhisper.jvm.memorystruct.HeapOOM.main(HeapOOM.java:17) + */ \ No newline at end of file diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/HelloWorld.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/HelloWorld.java new file mode 100644 index 00000000..ecbb75aa --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/HelloWorld.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.jvm.memorystruct; + +/** + * 元空间,堆,线程独占部分间的关系-内存角度 + * @author lastwhisper + */ +public class HelloWorld { + private static int id=10;//类变量 + private String name;//成员变量, + + public void setName(String name) { + this.name = name; + } + + public static void main(String[] args) { + int a = 1;//局部变量 + HelloWorld hw = new HelloWorld(); + hw.setName("testStr"); + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Increment.class b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Increment.class new file mode 100644 index 00000000..6c034467 Binary files /dev/null and b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Increment.class differ diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Increment.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Increment.java new file mode 100644 index 00000000..f33d89a0 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Increment.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.jvm.memorystruct; + +/** + * 栈帧中i++引发的问题 + * @author lastwhisper + * @date 2019/10/25 + */ +public class Increment { + public int increment() { + int i = 0; + i = i++; + return i; + } +} 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 new file mode 100644 index 00000000..745ca766 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/InternDifference.java @@ -0,0 +1,64 @@ +package cn.lastwhisper.jvm.memorystruct; + +/** + * Jdk6、7字符串常量池在永久代;jdk8字符串常量池在堆中 + * 1.jdk6环境下String.intern(); + * 如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象 + * 否则,将此String对象包含的字符串添加到常量池中,并返回此String对象的引用。 + * false false + * 2.jdk7环境下String.intern(); + * 如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象 + * 否则,如果该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) { + String s1 = new String("a"); + s1.intern(); + String s2 = "a"; + System.out.println("str1==str2:" + (s1 == s2)); + + String s3 = new String("a") + new String("a"); + s3.intern(); + String s4 = "aa"; + System.out.println("str1==str2:" + (s3 == s4)); + + String str1 = "abcd"; + String str2 = new String("abcd"); + System.out.println("str1==str2:" + (str1 == str2)); + + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/MethodAreaOOM.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/MethodAreaOOM.java new file mode 100644 index 00000000..5e100ef3 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/MethodAreaOOM.java @@ -0,0 +1,34 @@ +package cn.lastwhisper.jvm.memorystruct; + +import org.springframework.cglib.proxy.Enhancer; +import org.springframework.cglib.proxy.MethodInterceptor; +import org.springframework.cglib.proxy.MethodProxy; + +import java.lang.reflect.Method; + +/** + * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M + * @author zzm + */ +public class MethodAreaOOM { + + public static void main(String[] args) { + while (true) { + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(OOMObject.class); + enhancer.setUseCache(false); + enhancer.setCallback(new MethodInterceptor() { + @Override + public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { + return proxy.invokeSuper(obj, args); + } + }); + enhancer.create(); + } + } + + static class OOMObject { + + } +} + diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/PermGenOOM.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/PermGenOOM.java new file mode 100644 index 00000000..362cfe6c --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/PermGenOOM.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.jvm.memorystruct; + +import java.util.ArrayList; +import java.util.List; + +/** + * 1.jdk6环境下,String.intern(),运行时常量池导致的内存溢出异常 + * Exception in Thread "main" java.lang.OutOfMemoryError: PermGen space + * at java.lang.String.intern(Native Method) + * at cn.lastwhisper.jvm.memorystruct.PermGenOOM.main(PermGenOOM.java from InputFileObject:16) + * intern()将堆中String对象,复制到常量池 + * 2.jdk7环境下,不会内存溢出 + * intern()常量池引用堆中String对象 + * 3.jdk8环境下,不会内存溢出,并提示 + * Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option PermSize; support was removed in 8.0 + * Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0 + * + * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M + * @author lastwhisper + */ +public class PermGenOOM { + public static void main(String[] args) { + // 使用List保持着常量池引用,避免Full GC回收常量池行为 + List list = new ArrayList(); + for (int i = 0; ; i++) { + list.add(String.valueOf(i).intern()); + } + } +} \ No newline at end of file diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/StackSOF.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/StackSOF.java new file mode 100644 index 00000000..04e814b2 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/StackSOF.java @@ -0,0 +1,33 @@ +package cn.lastwhisper.jvm.memorystruct; + +/** + * 测试栈溢出 + * VM Args:-Xss180k + * @author lastwhisper + */ +public class StackSOF { + + private int stackLength = 1; + + public void stackLeak() { + stackLength++; + stackLeak(); + } + + public static void main(String[] args) throws Throwable { + StackSOF oom = new StackSOF(); + try { + oom.stackLeak(); + } catch (Throwable e) { + System.out.println("stack length:" + oom.stackLength); + throw e; + } + } +} +/** + * stack length:1549 + * Exception in Thread "main" java.lang.StackOverflowError + * at cn.lastwhisper.jvm.memorystruct.StackSOF.stackLeak(StackSOF.java:13) + * at cn.lastwhisper.jvm.memorystruct.StackSOF.stackLeak(StackSOF.java:14) + * at cn.lastwhisper.jvm.memorystruct.StackSOF.stackLeak(StackSOF.java:14) + */ \ No newline at end of file diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/TestStr.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/TestStr.java new file mode 100644 index 00000000..9e4204d6 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/TestStr.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.jvm.memorystruct; + +public class TestStr { + public static void main(String[] args) { + // 测试优化环境jdk8 + // 2.测试"ab"是否影响String s2=new String("a"+"b"); +// String s1 = "ab"; + // 1.测试"a"+"b"是否被jit编译器优化为"ab" + // 优化为String s2=new String("ab"); +// String s2=new String("a"+"b"); + // 3.测试new String("a")+new String("a")是否会被优化 + // 编译器优化为String s = (new StringBuilder()).append(new String("a")).append(new String("a")).toString(); + //String s3 = new String("a")+new String("a"); + /*4.String拼接*/ + //String str1 = "str"; + //String str2 = "ing"; + //String str3 = "str" + "ing";//常量池中的对象 + //String str4 = str1 + str2; //在堆上创建的新的对象 + //String str5 = "string";//常量池中的对象 + //System.out.println(str3 == str4);//false + //System.out.println(str3 == str5);//true + //System.out.println(str4 == str5);//false + String s1 = new String("abc");// 堆内存的地址值 + String s2 = "abc"; + System.out.println(s1 == s2);// 输出false,因为一个是堆内存,一个是常量池的内存,故两者是不同的。 + System.out.println(s1.equals(s2));// 输出true + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/TestStr2.class b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/TestStr2.class new file mode 100644 index 00000000..02b98c25 Binary files /dev/null and b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/TestStr2.class differ diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/TestStr2.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/TestStr2.java new file mode 100644 index 00000000..f079cdce --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/TestStr2.java @@ -0,0 +1,16 @@ +package cn.lastwhisper.jvm.memorystruct; + +/** + * @author lastwhisper + */ +public class TestStr2 { + /** + * 共产生几个String对象?5个 + */ + public static void main(String[] args) { + String s = "a"; + s = s + "b" + "c"; + s = s + "b" + "c" + "d"; + System.out.println(s); + } +} 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/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 new file mode 100644 index 00000000..7243315b --- /dev/null +++ b/mvc/pom.xml @@ -0,0 +1,17 @@ + + + + 4.0.0 + + 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������ʱ��������� + +1��Servlet����������ɨ�裬��ǰӦ������ÿһ��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.png���������Dz�����*.jsp�� + // /*����������������*.jspҳ�涼���أ�jspҳ����tomcat��jsp��������ģ� + @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; + } + + /** + * 1������������Callable + * 2��Spring�첽��������Callable �ύ�� TaskExecutor ʹ��һ��������߳̽���ִ�� + * 3��DispatcherServlet�����е�Filter�˳�web�������̣߳�����response ���ִ�״̬�� + * 4��Callable���ؽ����SpringMVC�����������ɷ����������ָ�֮ǰ�Ĵ����� + * 5������Callable���صĽ����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����ԭ��API��AsyncListener + * 2����SpringMVC��ʵ��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 new file mode 100644 index 00000000..5be68def --- /dev/null +++ b/mvc/springmvc/pom.xml @@ -0,0 +1,92 @@ + + + + + mvc + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + springmvc + war + + + springmvc Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + org.springframework + spring-webmvc + 4.3.11.RELEASE + + + + org.springframework + spring-webmvc + 4.3.11.RELEASE + + + javax.servlet + servlet-api + 2.5 + + + javax.servlet.jsp + jsp-api + 2.0 + + + + + springmvc + + + + 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-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + 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/ControllerDemo1.java b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo1.java new file mode 100644 index 00000000..cd52b1a5 --- /dev/null +++ b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo1.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * 处理器映射器 DispatcherServlet.initHandlerMappings + * @author lastwhisper + */ +@Controller +public class ControllerDemo1 { + + /** + * 处理请求的控制器方法 + * @return + */ + @RequestMapping("hello") + public String sayHello() { + System.out.println("控制器方法执行了"); + return "success"; + } + + @RequestMapping("hello2") + public String sayHello2() { + System.out.println("控制器方法执行了 2"); + return "success"; + } + +} diff --git a/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo2.java b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo2.java new file mode 100644 index 00000000..ac1521b7 --- /dev/null +++ b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo2.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.controller; + +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 处理器适配器 DispatcherServlet.getHandlerAdapter + * @author lastwhisper + */ +public class ControllerDemo2 implements Controller { + + @Override + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + ModelAndView mv = new ModelAndView(); + mv.setViewName("success2"); + return mv; + } + +} diff --git a/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo3.java b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo3.java new file mode 100644 index 00000000..51bd3c72 --- /dev/null +++ b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo3.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.controller; + +import org.springframework.web.HttpRequestHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 处理器适配器 DispatcherServlet.getHandlerAdapter + * 适配器模式 + * @author lastwhisper + */ +public class ControllerDemo3 implements HttpRequestHandler { + + @Override + public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.getRequestDispatcher("/WEB-INF/pages/success3.jsp").forward(request, response); + } + +} diff --git a/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo4.java b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo4.java new file mode 100644 index 00000000..2aa07481 --- /dev/null +++ b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo4.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * 基于注解配置控制器 + * 实现接收浏览器的异步请求,并返回json + * @author lastwhisper + */ +@Controller() +@RequestMapping("springmvc") +public class ControllerDemo4 { + + /** + * 使用response对象的getWriter()获取流对象,用流输出 + */ + @RequestMapping("testajax") + 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}"); + } + +} 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 new file mode 100644 index 00000000..c82364a1 --- /dev/null +++ b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ParameterController1.java @@ -0,0 +1,73 @@ +package cn.lastwhisper.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * 请求参数的封装分析 + */ +@Controller +public class ParameterController1 { + + /** + * 请求参数封装的分析(通过HandlerMethodArgumentResolver接口下的各种实现类) + * + * 请求调用链 + * DispatcherServlet.doDispatch + * AbstractHandlerMethodAdapter.handle + * RequestMappingHandlerAdapter.handleInternal + * invokeHandlerMethod + * ServletInvocableHandlerMethod.invokeAndHandle + * InvocableHandlerMethod.invokeForRequest + * getMethodArgumentValues + * RequestParamMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.resolveArgument) + * resolveName + * + * HandlerMethodArgumentResolver策略模式 + * @param username + * @param age + */ + @RequestMapping("testParam1") + public String testParam(String username, Integer age) { + System.out.println(username + "," + age); + return "success"; + } + + /** + * RequestParam的封装分析 + * RequestParamMethodArgumentResolver的resolveName + */ + @RequestMapping("testParam2") + public String testParam2(@RequestParam("username") String name, Integer age) { + System.out.println(name + "," + age); + return "success"; + } + + + /** + * RequestBody的封装分析 + * RequestResponseBodyMethodProcessor.resolveArgument + * readWithMessageConverters + * + */ + @RequestMapping("testParam3") + public void testParam3(@RequestBody String body) { + System.out.println(body); + } + + /** + * PathVariable的封装分析 + * PathVariableMethodArgumentResolver.resolveName + * handleResolvedValue + */ + @RequestMapping("testParam4/{username}/{age}") + public void testParam4(@PathVariable("username") String username, @PathVariable Integer age){ + 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 new file mode 100644 index 00000000..a3dd1939 --- /dev/null +++ b/mvc/springmvc/src/main/resources/springmvc.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mvc/springmvc/src/main/webapp/WEB-INF/pages/success.jsp b/mvc/springmvc/src/main/webapp/WEB-INF/pages/success.jsp new file mode 100644 index 00000000..b88615df --- /dev/null +++ b/mvc/springmvc/src/main/webapp/WEB-INF/pages/success.jsp @@ -0,0 +1,16 @@ +<%-- + Created by IntelliJ IDEA. + User: Administrator + Date: 2019/9/17 + Time: 18:12 + To change this template use File | Settings | File Templates. +--%> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + 成功页面 + + +执行成功 + + diff --git a/mvc/springmvc/src/main/webapp/WEB-INF/pages/success2.jsp b/mvc/springmvc/src/main/webapp/WEB-INF/pages/success2.jsp new file mode 100644 index 00000000..7b8952a8 --- /dev/null +++ b/mvc/springmvc/src/main/webapp/WEB-INF/pages/success2.jsp @@ -0,0 +1,16 @@ +<%-- + Created by IntelliJ IDEA. + User: Administrator + Date: 2019/9/17 + Time: 18:12 + To change this template use File | Settings | File Templates. +--%> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + 成功页面 + + +由Controller接口的实现类执行的结果 + + diff --git a/mvc/springmvc/src/main/webapp/WEB-INF/pages/success3.jsp b/mvc/springmvc/src/main/webapp/WEB-INF/pages/success3.jsp new file mode 100644 index 00000000..027d5541 --- /dev/null +++ b/mvc/springmvc/src/main/webapp/WEB-INF/pages/success3.jsp @@ -0,0 +1,16 @@ +<%-- + Created by IntelliJ IDEA. + User: Administrator + Date: 2019/9/17 + Time: 18:12 + To change this template use File | Settings | File Templates. +--%> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + 成功页面 + + +由HttpRequestHandler接口的实现类执行的结果 + + diff --git a/mvc/springmvc/src/main/webapp/WEB-INF/web.xml b/mvc/springmvc/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..4833a738 --- /dev/null +++ b/mvc/springmvc/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,25 @@ + + + + + + dispatcherServlet + org.springframework.web.servlet.DispatcherServlet + + + contextConfigLocation + classpath:springmvc.xml + + + 1 + + + dispatcherServlet + / + + + + \ No newline at end of file diff --git a/mvc/springmvc/src/main/webapp/index.jsp b/mvc/springmvc/src/main/webapp/index.jsp new file mode 100644 index 00000000..f8ba8431 --- /dev/null +++ b/mvc/springmvc/src/main/webapp/index.jsp @@ -0,0 +1,56 @@ +<%@page language="java" pageEncoding="UTF-8" contentType="text/html;charset=UTF-8" %> + + + 主页面 + + + + + +
+
+
+

请求参数封装的连接

+请求参数封装原理分析 +
+RequestParam分析 +
+RequestBody分析 +
+PathVariable分析 +
+

文件下载分析

+文件下载分析 +
+ + diff --git a/mvc/springmvc/src/main/webapp/js/jquery.min.js b/mvc/springmvc/src/main/webapp/js/jquery.min.js new file mode 100644 index 00000000..4024b662 --- /dev/null +++ b/mvc/springmvc/src/main/webapp/js/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v2.2.4 | (c) jQuery Foundation | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isPlainObject:function(a){var b;if("object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype||{},"isPrototypeOf"))return!1;for(b in a);return void 0===b||k.call(a,b)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=d.createElement("script"),b.text=a,d.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:h.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(d=e.call(arguments,2),f=function(){return a.apply(b||this,d.concat(e.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return h.call(b,a)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&f.parentNode&&(this.length=1,this[0]=f),this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?void 0!==c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?h.call(n(a),this[0]):h.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||n.uniqueSort(e),D.test(a)&&e.reverse()),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.removeEventListener("DOMContentLoaded",J),a.removeEventListener("load",J),n.ready()}n.ready.promise=function(b){return I||(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(n.ready):(d.addEventListener("DOMContentLoaded",J),a.addEventListener("load",J))),I.promise(b)},n.ready.promise();var K=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)K(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},L=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function M(){this.expando=n.expando+M.uid++}M.uid=1,M.prototype={register:function(a,b){var c=b||{};return a.nodeType?a[this.expando]=c:Object.defineProperty(a,this.expando,{value:c,writable:!0,configurable:!0}),a[this.expando]},cache:function(a){if(!L(a))return{};var b=a[this.expando];return b||(b={},L(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[b]=c;else for(d in b)e[d]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=a[this.expando];if(void 0!==f){if(void 0===b)this.register(a);else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in f?d=[b,e]:(d=e,d=d in f?[d]:d.match(G)||[])),c=d.length;while(c--)delete f[d[c]]}(void 0===b||n.isEmptyObject(f))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!n.isEmptyObject(b)}};var N=new M,O=new M,P=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Q=/[A-Z]/g;function R(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Q,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:P.test(c)?n.parseJSON(c):c; +}catch(e){}O.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),R(f,d,e[d])));N.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){O.set(this,a)}):K(this,function(b){var c,d;if(f&&void 0===b){if(c=O.get(f,a)||O.get(f,a.replace(Q,"-$&").toLowerCase()),void 0!==c)return c;if(d=n.camelCase(a),c=O.get(f,d),void 0!==c)return c;if(c=R(f,d,void 0),void 0!==c)return c}else d=n.camelCase(a),this.each(function(){var c=O.get(this,d);O.set(this,d,b),a.indexOf("-")>-1&&void 0!==c&&O.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){O.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=N.get(a,b),c&&(!d||n.isArray(c)?d=N.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return N.get(a,c)||N.access(a,c,{empty:n.Callbacks("once memory").add(function(){N.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length",""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};$.optgroup=$.option,$.tbody=$.tfoot=$.colgroup=$.caption=$.thead,$.th=$.td;function _(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function aa(a,b){for(var c=0,d=a.length;d>c;c++)N.set(a[c],"globalEval",!b||N.get(b[c],"globalEval"))}var ba=/<|&#?\w+;/;function ca(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],o=0,p=a.length;p>o;o++)if(f=a[o],f||0===f)if("object"===n.type(f))n.merge(m,f.nodeType?[f]:f);else if(ba.test(f)){g=g||l.appendChild(b.createElement("div")),h=(Y.exec(f)||["",""])[1].toLowerCase(),i=$[h]||$._default,g.innerHTML=i[1]+n.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;n.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",o=0;while(f=m[o++])if(d&&n.inArray(f,d)>-1)e&&e.push(f);else if(j=n.contains(f.ownerDocument,f),g=_(l.appendChild(f),"script"),j&&aa(g),c){k=0;while(f=g[k++])Z.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ja(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ha;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return"undefined"!=typeof n&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(G)||[""],j=b.length;while(j--)h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.hasData(a)&&N.get(a);if(r&&(i=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&N.remove(a,"handle events")}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(N.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,la=/\s*$/g;function pa(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function qa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function ra(a){var b=na.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function sa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(N.hasData(a)&&(f=N.access(a),g=N.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}O.hasData(a)&&(h=O.access(a),i=n.extend({},h),O.set(b,i))}}function ta(a,b){var c=b.nodeName.toLowerCase();"input"===c&&X.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function ua(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&ma.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),ua(f,b,c,d)});if(o&&(e=ca(b,a[0].ownerDocument,!1,a,d),g=e.firstChild,1===e.childNodes.length&&(e=g),g||d)){for(h=n.map(_(e,"script"),qa),i=h.length;o>m;m++)j=e,m!==p&&(j=n.clone(j,!0,!0),i&&n.merge(h,_(j,"script"))),c.call(a[m],j,m);if(i)for(k=h[h.length-1].ownerDocument,n.map(h,ra),m=0;i>m;m++)j=h[m],Z.test(j.type||"")&&!N.access(j,"globalEval")&&n.contains(k,j)&&(j.src?n._evalUrl&&n._evalUrl(j.src):n.globalEval(j.textContent.replace(oa,"")))}return a}function va(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(_(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&aa(_(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(ka,"<$1>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=_(h),f=_(a),d=0,e=f.length;e>d;d++)ta(f[d],g[d]);if(b)if(c)for(f=f||_(a),g=g||_(h),d=0,e=f.length;e>d;d++)sa(f[d],g[d]);else sa(a,h);return g=_(h,"script"),g.length>0&&aa(g,!i&&_(a,"script")),h},cleanData:function(a){for(var b,c,d,e=n.event.special,f=0;void 0!==(c=a[f]);f++)if(L(c)){if(b=c[N.expando]){if(b.events)for(d in b.events)e[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);c[N.expando]=void 0}c[O.expando]&&(c[O.expando]=void 0)}}}),n.fn.extend({domManip:ua,detach:function(a){return va(this,a,!0)},remove:function(a){return va(this,a)},text:function(a){return K(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.appendChild(a)}})},prepend:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(_(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return K(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!la.test(a)&&!$[(Y.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(_(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return ua(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(_(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),f=e.length-1,h=0;f>=h;h++)c=h===f?this:this.clone(!0),n(e[h])[b](c),g.apply(d,c.get());return this.pushStack(d)}});var wa,xa={HTML:"block",BODY:"block"};function ya(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function za(a){var b=d,c=xa[a];return c||(c=ya(a,b),"none"!==c&&c||(wa=(wa||n("