From c6e4b604241d2e599de2c8842cfc61e7ee9c3989 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Mon, 28 Sep 2020 15:46:34 +0800 Subject: [PATCH 1/3] kafka-manager 2.0 --- Dockerfile | 7 - README.md | 95 +- common/pom.xml | 50 - .../manager/common/constant/Constant.java | 21 - .../manager/common/constant/MetricsType.java | 23 - .../common/constant/OffsetStoreLocation.java | 35 - .../manager/common/constant/StatusCode.java | 35 - .../monitor/MonitorConditionType.java | 71 - .../constant/monitor/MonitorMatchStatus.java | 19 - .../constant/monitor/MonitorMetricsType.java | 59 - .../constant/monitor/MonitorNotifyType.java | 56 - .../common/entity/ConsumerMetrics.java | 69 - .../entity/annotations/FieldSelector.java | 24 - .../entity/bizenum/AccountRoleEnum.java | 35 - .../entity/bizenum/AdminTopicStatusEnum.java | 38 - .../common/entity/bizenum/DBStatusEnum.java | 42 - .../common/entity/bizenum/OperationEnum.java | 19 - .../common/entity/bizenum/OrderTypeEnum.java | 33 - .../bizenum/PreferredReplicaElectEnum.java | 31 - .../bizenum/ReassignmentStatusEnum.java | 45 - .../common/entity/dto/BrokerOverallDTO.java | 132 - .../common/entity/dto/BrokerOverviewDTO.java | 121 - .../common/entity/dto/ControllerDTO.java | 70 - .../common/entity/dto/TopicBasicDTO.java | 123 - .../common/entity/dto/TopicOverviewDTO.java | 86 - .../common/entity/dto/TopicPartitionDTO.java | 105 - .../entity/dto/alarm/AlarmNotifyDTO.java | 47 - .../common/entity/dto/alarm/AlarmRuleDTO.java | 127 - .../dto/alarm/AlarmStrategyActionDTO.java | 43 - .../dto/alarm/AlarmStrategyExpressionDTO.java | 68 - .../dto/alarm/AlarmStrategyFilterDTO.java | 44 - .../common/entity/metrics/BaseMetrics.java | 394 - .../common/entity/metrics/BrokerMetrics.java | 331 - .../common/entity/metrics/TopicMetrics.java | 68 - .../manager/common/entity/po/AlarmRuleDO.java | 68 - .../manager/common/entity/po/BaseDO.java | 59 - .../manager/common/entity/po/BaseEntryDO.java | 37 - .../common/entity/po/ClusterMetricsDO.java | 110 - .../common/entity/po/MigrationTaskDO.java | 96 - .../common/entity/po/OrderPartitionDO.java | 134 - .../common/entity/po/OrderTopicDO.java | 178 - .../manager/common/entity/po/RegionDO.java | 63 - .../manager/common/entity/po/TopicDO.java | 68 - .../common/entity/po/TopicFavoriteDO.java | 46 - .../entity/po/query/AlarmRuleQueryOption.java | 17 - .../entity/po/query/BaseQueryOption.java | 24 - .../entity/po/query/ClusterQueryOption.java | 17 - .../kafka/manager/common/utils/DateUtils.java | 15 - .../common/utils/jmx/JmxConnectorWrap.java | 72 - .../common/utils/jmx/MbeanNameUtil.java | 93 - .../common/utils/zk/StateChangeListener.java | 17 - .../manager/common/utils/zk/ZkPathUtil.java | 165 - console/package-lock.json | 9510 ----------------- .../src/container/admin-consume/detail.tsx | 69 - .../src/container/admin-consume/index.less | 8 - console/src/container/admin-consume/index.tsx | 69 - .../src/container/admin-controller/index.tsx | 87 - .../container/admin-home/cluster-detail.tsx | 60 - console/src/container/admin-home/index.less | 9 - console/src/container/admin-home/index.tsx | 133 - .../src/container/admin-operation/index.tsx | 138 - console/src/container/admin-order/index.less | 16 - console/src/container/admin-order/index.tsx | 171 - console/src/container/admin-region/index.tsx | 138 - console/src/container/admin-topic/index.tsx | 148 - .../src/container/admin-usermanage/index.less | 12 - .../src/container/admin-usermanage/index.tsx | 97 - console/src/container/alarm/index.tsx | 135 - .../container/broker-detail/base-detail.tsx | 82 - .../container/broker-detail/broker-index.tsx | 90 - .../broker-detail/broker-partition.tsx | 109 - .../src/container/broker-detail/constant.ts | 64 - console/src/container/broker-detail/index.tsx | 37 - .../broker-detail/topic-analysis.tsx | 94 - .../container/broker-detail/topic-info.tsx | 102 - .../src/container/broker-info/base-info.tsx | 255 - .../container/broker-info/broker-overview.tsx | 79 - console/src/container/broker-info/constant.ts | 5 - console/src/container/broker-info/index.less | 84 - console/src/container/broker-info/index.tsx | 21 - console/src/container/cluster-topic/index.tsx | 98 - console/src/container/consumer/index.less | 34 - console/src/container/consumer/index.tsx | 111 - console/src/container/drawer/index.less | 31 - console/src/container/drawer/index.tsx | 19 - console/src/container/drawer/reset-offset.tsx | 118 - console/src/container/drawer/topic-sample.tsx | 103 - console/src/container/header/index.less | 103 - console/src/container/header/index.tsx | 56 - console/src/container/left-menu/constant.ts | 79 - console/src/container/left-menu/index.tsx | 57 - console/src/container/modal/admin-expand.tsx | 141 - console/src/container/modal/alarm-config.tsx | 303 - .../src/container/modal/cluster-network.tsx | 24 - console/src/container/modal/cluster.tsx | 173 - console/src/container/modal/cosumer-topic.tsx | 42 - console/src/container/modal/index.tsx | 47 - .../src/container/modal/leader-rebalance.tsx | 112 - console/src/container/modal/new-user.tsx | 110 - console/src/container/modal/order-approve.tsx | 250 - .../src/container/modal/partition-approve.tsx | 209 - console/src/container/modal/region.tsx | 171 - console/src/container/modal/reset-offset.tsx | 78 - console/src/container/modal/task-new.tsx | 200 - console/src/container/modal/topic-create.tsx | 220 - console/src/container/modal/topic-expand.tsx | 138 - console/src/container/modal/topic-new.tsx | 142 - console/src/container/modify-user/index.less | 45 - console/src/container/modify-user/index.tsx | 83 - console/src/container/my-order/index.tsx | 205 - console/src/container/topic-detail/com.tsx | 198 - console/src/container/topic-detail/index.less | 173 - console/src/container/topic-detail/index.tsx | 302 - console/src/container/user-home/index.less | 73 - console/src/container/user-home/index.tsx | 286 - console/src/lib/api.ts | 379 - console/src/lib/charts-config.ts | 141 - console/src/lib/fetch.ts | 86 - console/src/lib/utils.ts | 65 - console/src/routers/page/admin/index.tsx | 71 - console/src/routers/page/home/index.tsx | 43 - console/src/routers/router.tsx | 49 - console/src/store/alarm.ts | 54 - console/src/store/broker.ts | 266 - console/src/store/cluster.ts | 128 - console/src/store/controller.ts | 25 - console/src/store/drawer.ts | 31 - console/src/store/modal.ts | 147 - console/src/store/operation.ts | 66 - console/src/store/order.ts | 73 - console/src/store/region.ts | 36 - console/src/store/topic.ts | 239 - console/src/store/users.ts | 34 - console/src/types/base-type.ts | 218 - .../kafka/manager/dao/AlarmRuleDao.java | 17 - .../kafka/manager/dao/MigrationTaskDao.java | 38 - .../manager/dao/OperationHistoryDao.java | 11 - .../kafka/manager/dao/OrderPartitionDao.java | 17 - .../kafka/manager/dao/OrderTopicDao.java | 19 - .../kafka/manager/dao/TopicFavoriteDao.java | 15 - .../manager/dao/impl/AlarmRuleDaoImpl.java | 55 - .../dao/impl/KafkaManagerProperties.java | 22 - .../dao/impl/MigrationTaskDaoImpl.java | 55 - .../dao/impl/OperationHistoryDaoImpl.java | 26 - .../dao/impl/OrderPartitionDaoImpl.java | 48 - .../manager/dao/impl/OrderTopicDaoImpl.java | 53 - .../kafka/manager/dao/impl/TopicDaoImpl.java | 67 - .../dao/impl/TopicFavoriteDaoImpl.java | 84 - .../manager/dao/impl/TopicMetricsDaoImpl.java | 47 - dao/src/main/resources/mapper/AccountDao.xml | 52 - .../main/resources/mapper/AlarmRuleDao.xml | 57 - dao/src/main/resources/mapper/BrokerDao.xml | 40 - .../resources/mapper/BrokerMetricsDao.xml | 48 - dao/src/main/resources/mapper/ClusterDao.xml | 59 - .../resources/mapper/ClusterMetricsDao.xml | 37 - .../resources/mapper/MigrationTaskDao.xml | 46 - .../resources/mapper/OperationHistoryDao.xml | 21 - .../resources/mapper/OrderPartitionDao.xml | 68 - .../main/resources/mapper/OrderTopicDao.xml | 75 - dao/src/main/resources/mapper/RegionDao.xml | 60 - dao/src/main/resources/mapper/TopicDao.xml | 50 - .../resources/mapper/TopicFavoriteDao.xml | 44 - .../main/resources/mapper/TopicMetricsDao.xml | 37 - dao/src/main/resources/spring-dao.xml | 95 - .../admin_add_cluster.jpg | Bin 47116 -> 0 bytes .../admin_cluster_broker_detail.jpg | Bin 66049 -> 0 bytes .../admin_cluster_details.jpg | Bin 55607 -> 0 bytes .../admin_manager_account.jpg | Bin 44585 -> 0 bytes .../kafka_manager_cn_guide/admin_order.jpg | Bin 48364 -> 0 bytes .../kafka_manager_cn_guide/my_order_list.jpg | Bin 49500 -> 0 bytes .../normal_create_alarm_rule.jpg | Bin 48729 -> 0 bytes .../normal_modify_password.jpg | Bin 38847 -> 0 bytes .../normal_reset_consume_offset.jpg | Bin 57077 -> 0 bytes .../normal_topic_detail.jpg | Bin 67590 -> 0 bytes doc/create_mysql_table.sql | 243 - doc/create_postgresql_table.sql | 325 - docker-compose.yml | 32 - docker/kafka-manager/Dockerfile | 7 - .../kafka-manager/application-standalone.yml | 32 - docker/kafka-manager/application.yml | 32 - docker/mysql/Dockerfile | 3 - docker/mysql/create_mysql_table.sql | 243 - {doc => docs}/assets/images/common/arch.png | Bin .../assets/images/common/dingding_group.jpg | Bin .../assets/images/common/logo_name.png | Bin docs/create_mysql_table.sql | 577 + docs/install_cn_guide.md | 58 + docs/manual_kafka_op/add_cluster.md | 39 + docs/manual_kafka_op/imgs/op_add_cluster.jpg | Bin 0 -> 267141 bytes .../imgs/op_add_logical_cluster.jpg | Bin 0 -> 245285 bytes docs/manual_kafka_op/imgs/op_add_region.jpg | Bin 0 -> 200029 bytes {doc => docs}/user_cn_guide.md | 0 kafka-manager-common/pom.xml | 105 + .../manager/common/annotations/ApiLevel.java | 24 + .../common/bizenum/AccountRoleEnum.java | 50 + .../manager/common/bizenum/ApiLevelEnum.java | 19 + .../common/bizenum/ClusterComboEnum.java | 37 + .../common/bizenum/ClusterModeEnum.java | 48 + .../manager/common/bizenum/DBStatusEnum.java | 25 + .../kafka/manager/common/bizenum/IDCEnum.java | 45 + .../common/bizenum/KafkaBrokerRoleEnum.java | 34 + .../common/bizenum/KafkaClientEnum.java | 46 + .../manager/common/bizenum/KafkaFileEnum.java | 54 + .../manager/common/bizenum/ModuleEnum.java | 76 + .../common/bizenum/OffsetLocationEnum.java | 36 + .../manager/common/bizenum/OffsetPosEnum.java | 42 + .../manager/common/bizenum/OperateEnum.java | 59 + .../common/bizenum/OperationStatusEnum.java | 30 + .../common/bizenum/PeakFlowStatusEnum.java | 50 + .../bizenum/RebalanceDimensionEnum.java | 31 + .../common/bizenum/SinkMonitorSystemEnum.java | 45 + .../common/bizenum/TaskStatusEnum.java | 72 + .../bizenum/TaskStatusReassignEnum.java | 55 + .../common/bizenum/TopicAuthorityEnum.java | 36 + .../bizenum/TopicOffsetChangedEnum.java | 45 + .../bizenum/TopicReassignActionEnum.java | 39 + .../bizenum/gateway/GatewayConfigKeyEnum.java | 48 + .../common/constant/ApiLevelContent.java | 15 + .../manager/common/constant/ApiPrefix.java | 26 + .../common/constant/ConfigConstant.java | 33 + .../manager/common/constant/Constant.java | 48 + .../common/constant/KafkaConstant.java | 17 + .../constant/KafkaMetricsCollections.java | 42 + .../manager/common/constant/LogConstant.java | 13 + .../common/constant/LoginConstant.java | 14 + .../common/constant/SystemCodeConstant.java | 17 + .../constant/TopicCreationConstant.java | 49 + .../common/constant/TopicSampleConstant.java | 19 + .../common/entity/ConsumerMetadata.java | 12 +- .../entity/DeprecatedResponseResult.java | 83 + .../manager/common/entity/KafkaVersion.java | 82 + .../kafka/manager/common/entity/Result.java | 43 +- .../manager/common/entity/ResultStatus.java | 154 + .../common/entity/TopicOperationResult.java | 83 + .../manager/common/entity/ao/AppTopicDTO.java | 91 + .../common/entity/ao}/BrokerBasicDTO.java | 2 +- .../common/entity/ao/BrokerOverviewDTO.java | 189 + .../common/entity/ao/ClusterDetailDTO.java | 183 +- .../entity/ao/PartitionAttributeDTO.java | 24 + .../common/entity/ao}/PartitionOffsetDTO.java | 2 +- .../common/entity/ao/RdTopicBasic.java | 103 + .../common/entity/ao/TopicDiskLocation.java | 103 + .../common/entity/ao/account/Account.java | 71 + .../ao}/analysis/AnalysisBrokerDTO.java | 2 +- .../entity/ao}/analysis/AnalysisTopicDTO.java | 2 +- .../common/entity/ao/api/ApiCount.java | 50 + .../ao/cluster/ClusterBrokerStatus.java | 37 + .../entity/ao/cluster/LogicalCluster.java | 123 + .../ao/cluster/LogicalClusterMetrics.java | 65 +- .../entity/ao/config/CreateTopicConfig.java | 26 + .../ao/config/CreateTopicElemConfig.java | 104 +- .../entity/ao/config/MaxAvgBytesInConfig.java | 25 + .../SinkTopicRequestTimeMetricsConfig.java | 57 + .../ao/config/TopicAnomalyFlowConfig.java | 57 + .../entity/ao/config/TopicNameConfig.java | 44 + .../config/expert/RegionTopicHotConfig.java | 58 + .../ao/config/expert/TopicExpiredConfig.java | 38 + .../TopicInsufficientPartitionConfig.java | 50 + .../entity/ao}/consumer/ConsumeDetailDTO.java | 2 +- .../entity/ao}/consumer/ConsumerGroupDTO.java | 46 +- .../entity/ao/expert/TopicAnomalyFlow.java | 90 + .../ao/expert/TopicInsufficientPartition.java | 111 + .../entity/ao/expert/TopicRegionHot.java | 70 + .../entity/ao/gateway/AppRateConfig.java | 30 + .../entity/ao/gateway/BaseGatewayConfig.java | 24 + .../entity/ao/gateway/IpRateConfig.java | 30 + .../gateway/KafkaBootstrapServerConfig.java | 33 + .../entity/ao/gateway/RequestQueueConfig.java | 30 + .../entity/ao/gateway/SpRateConfig.java | 32 + .../common/entity/ao/gateway/TopicQuota.java | 68 + .../entity/ao/reassign/ReassignStatus.java | 130 + .../ao/remote/KafkaConsumerMetrics.java | 50 +- .../ao/remote/KafkaConsumerMetricsElem.java | 46 + .../entity/ao/remote/KafkaTopicMetrics.java | 79 + .../entity/ao/topic/MineTopicSummary.java | 123 + .../common/entity/ao/topic/TopicAppData.java | 123 + .../common/entity/ao/topic/TopicBasicDTO.java | 170 +- .../entity/ao/topic/TopicBrokerDTO.java | 81 + .../entity/ao/topic/TopicBusinessInfo.java | 68 + .../entity/ao/topic/TopicConnection.java | 90 + .../common/entity/ao/topic/TopicDTO.java | 101 + .../entity/ao/topic/TopicExpiredData.java | 71 + .../entity/ao/topic/TopicMetricsDTO.java | 147 + .../common/entity/ao/topic/TopicOverview.java | 146 + .../entity/ao/topic/TopicPartitionDTO.java | 78 +- .../common/entity/dto/ClusterTopicDTO.java | 25 +- .../common/entity/dto/config/ConfigDTO.java | 65 + .../entity/dto/gateway/KafkaAclSearchDTO.java | 61 + .../dto/gateway/KafkaUserSearchDTO.java | 51 + .../dto/gateway/TopicConnectionDTO.java | 127 + .../common/entity/dto/normal/AppDTO.java | 76 + .../entity/dto/normal/JmxSwitchDTO.java | 126 + .../entity/dto/normal/KafkaFileDTO.java | 143 + .../common/entity/dto/normal/LoginDTO.java | 33 +- .../entity/dto/normal/TopicDataSampleDTO.java | 100 + .../entity/dto/normal/TopicModifyDTO.java | 41 + .../dto/normal/TopicOffsetResetDTO.java | 139 + .../entity/dto/normal/TopicRetainDTO.java | 44 + .../common/entity/dto/op/KafkaPackageDTO.java | 25 + .../common/entity/dto/op/RebalanceDTO.java | 41 +- .../dto/op/reassign/ReassignExecDTO.java | 70 + .../dto/op/reassign/ReassignExecSubDTO.java | 92 + .../dto/op/reassign/ReassignTopicDTO.java | 172 + .../entity/dto/op/topic/TopicCreationDTO.java | 138 + .../entity/dto/op/topic/TopicDeletionDTO.java | 44 + .../dto/op/topic/TopicExpansionDTO.java | 71 + .../dto/op/topic/TopicModificationDTO.java | 85 + .../common/entity/dto/rd/AccountDTO.java | 42 +- .../common/entity/dto/rd/ClusterDTO.java | 128 + .../entity/dto/rd/CustomScheduledTaskDTO.java | 35 + .../entity/dto/rd/LogicalClusterDTO.java | 118 + .../entity/dto/rd/OperateRecordDTO.java | 91 + .../common/entity/dto/rd/RegionDTO.java | 100 +- .../common/entity/metrics/BaseMetrics.java | 159 + .../common/entity/metrics/BrokerMetrics.java | 42 + .../common/entity/metrics/ClusterMetrics.java | 29 + .../entity/metrics/ConsumerMetrics.java | 106 + .../common/entity/metrics/TopicMetrics.java | 48 + .../entity/metrics/TopicThrottledMetrics.java | 72 + .../common/entity/pojo}/AccountDO.java | 14 +- .../manager/common/entity/pojo}/BrokerDO.java | 67 +- .../common/entity/pojo/BrokerMetricsDO.java | 70 + .../common/entity/pojo}/ClusterDO.java | 161 +- .../common/entity/pojo/ClusterMetricsDO.java | 59 + .../common/entity/pojo/ClusterTaskDO.java | 213 + .../entity/pojo/ClusterTaskDetailDO.java | 103 + .../manager/common/entity/pojo/ConfigDO.java | 92 + .../common/entity/pojo}/ControllerDO.java | 28 +- .../common/entity/pojo/HeartbeatDO.java | 76 + .../common/entity/pojo/KafkaBillDO.java | 103 + .../common/entity/pojo/KafkaFileDO.java | 114 + .../common/entity/pojo/LogicalClusterDO.java | 114 + .../common/entity/pojo/MonitorRuleDO.java | 92 + .../common/entity/pojo/OperateRecordDO.java | 103 + .../entity/pojo}/OperationHistoryDO.java | 36 +- .../manager/common/entity/pojo/OrderDO.java | 147 + .../common/entity/pojo/ReassignTaskDO.java | 225 + .../manager/common/entity/pojo/RegionDO.java | 137 + .../manager/common/entity/pojo/TopicDO.java | 100 + .../common/entity/pojo/TopicExpiredDO.java | 103 + .../common/entity/pojo/TopicMetricsDO.java | 81 + .../common/entity/pojo/TopicStatisticsDO.java | 92 + .../entity/pojo/TopicThrottledMetricsDO.java | 92 + .../common/entity/pojo/gateway/AppDO.java | 148 + .../entity/pojo/gateway/AuthorityDO.java | 92 + .../entity/pojo/gateway/GatewayConfigDO.java | 92 + .../entity/pojo/gateway/KafkaAclDO.java | 92 + .../entity/pojo/gateway/KafkaUserDO.java | 81 + .../pojo/gateway/TopicConnectionDO.java | 108 + .../entity/pojo/gateway/TopicReportDO.java | 92 + .../entity/vo/common/AccountRoleVO.java | 46 + .../entity/vo/common/AccountSummaryVO.java | 53 + .../common/entity/vo/common/AccountVO.java | 65 + .../entity/vo/common/BrokerOverviewVO.java | 197 + .../entity/vo/common}/OrderPartitionVO.java | 2 +- .../entity/vo/common}/OrderTopicVO.java | 2 +- .../entity/vo/common/RealTimeMetricsVO.java | 19 +- .../entity/vo/common}/TopicOverviewVO.java | 102 +- .../entity/vo/common/TopicThrottleVO.java | 67 + .../entity/vo/gateway/GatewayConfigVO.java | 40 + .../common/entity/vo/gateway/KafkaAclVO.java | 68 + .../entity/vo/gateway/KafkaSecurityVO.java | 26 + .../common/entity/vo/gateway/KafkaUserVO.java | 68 + .../entity/vo/normal/BillStaffDetailVO.java | 55 + .../entity/vo/normal/BillStaffSummaryVO.java | 89 + .../common/entity/vo/normal/BillTopicVO.java | 77 + .../common/entity/vo/normal/QuotaVO.java | 68 + .../entity/vo/normal/TopicBusinessInfoVO.java | 77 + .../entity/vo/normal/app/AppSummaryVO.java | 53 + .../vo/normal/app/AppTopicAuthorityVO.java | 48 + .../entity/vo/normal/app/AppTopicVO.java | 77 +- .../common/entity/vo/normal/app/AppVO.java | 77 + .../entity/vo/normal/app/DeprecatedAppVO.java | 214 + .../vo/normal}/cluster/ClusterBasicVO.java | 2 +- .../vo/normal/cluster/ClusterNameDTO.java | 70 + .../vo/normal/cluster/LogicClusterVO.java | 138 + .../cluster/NormalClusterMetricsVO.java | 56 +- .../vo/normal/cluster/TopicMetadataVO.java | 55 + .../consumer/ConsumerGroupDetailVO.java | 27 +- .../vo/normal}/consumer/ConsumerGroupVO.java | 33 +- .../entity/vo/normal/order/OrderResultVO.java | 38 + .../entity/vo/normal/order/OrderTypeVO.java | 47 + .../entity/vo/normal/order/OrderVO.java | 101 + .../order/detail/OrderDetailBaseVO.java | 153 + .../vo/normal/topic/TopicAuthorizedAppVO.java | 125 + .../entity/vo/normal/topic/TopicBasicVO.java | 174 + .../entity/vo/normal/topic/TopicBillVO.java | 53 + .../vo/normal/topic/TopicConnectionVO.java | 101 + .../vo/normal}/topic/TopicDataSampleVO.java | 2 +- .../vo/normal}/topic/TopicDeleteVO.java | 2 +- .../vo/normal}/topic/TopicDetailVO.java | 3 +- .../vo/normal/topic/TopicExpiredVO.java | 101 + .../entity/vo/normal/topic/TopicMetricVO.java | 149 + .../entity/vo/normal/topic/TopicMineVO.java | 125 + .../entity/vo/normal/topic/TopicMyAppVO.java | 89 + .../vo/normal}/topic/TopicOffsetVO.java | 2 +- .../vo/normal/topic/TopicPartitionVO.java | 139 + .../topic/TopicRequestTimeDetailVO.java | 113 + .../vo/normal/topic/TopicRequestTimeVO.java | 149 + .../entity/vo/normal/topic/TopicVO.java | 113 + .../vo/op/expert/AnomalyFlowTopicVO.java | 101 + .../vo/op/expert/BrokerIdPartitionNumVO.java | 41 + .../entity/vo/op/expert/ExpiredTopicVO.java | 111 + .../expert/PartitionInsufficientTopicVO.java | 127 + .../entity/vo/op/expert/RegionHotTopicVO.java | 85 + .../reassign/ReassignPartitionStatusVO.java | 53 + .../entity/vo/op/reassign/ReassignTaskVO.java | 136 + .../vo/op/reassign/ReassignTopicStatusVO.java | 151 + .../vo/op/task/ClusterTaskKafkaFilesVO.java | 49 + .../vo/op/task/ClusterTaskMetadataVO.java | 187 + .../vo/op/task/ClusterTaskStatusVO.java | 127 + .../vo/op/task/ClusterTaskSubStatusVO.java | 65 + .../entity/vo/op/task/ClusterTaskVO.java | 99 + .../manager/common/entity/vo/rd/ConfigVO.java | 89 + .../entity/vo/rd/CustomScheduledTaskVO.java | 35 + .../entity/vo/rd/KafkaControllerVO.java | 65 + .../common/entity/vo/rd/KafkaFileVO.java | 127 + .../common/entity/vo/rd/OperateRecordVO.java | 139 + .../common/entity/vo/rd/RdTopicBasicVO.java | 115 + .../common/entity/vo/rd}/RegionVO.java | 105 +- .../common/entity/vo/rd}/TopicBrokerVO.java | 30 +- .../vo/rd}/broker/AnalysisBrokerVO.java | 2 +- .../entity/vo/rd}/broker/AnalysisTopicVO.java | 2 +- .../entity/vo/rd}/broker/BrokerBasicVO.java | 10 +- .../vo/rd/broker/BrokerDiskTopicVO.java | 115 + .../vo/rd}/broker/BrokerMetadataVO.java | 2 +- .../entity/vo/rd/broker/BrokerMetricsVO.java | 221 + .../vo/rd/broker/BrokerPartitionVO.java | 9 +- .../entity/vo/rd/broker/RdBrokerBasicVO.java | 53 + .../entity/vo/rd/cluster/ClusterBaseVO.java | 151 + .../vo/rd/cluster/ClusterBrokerStatusVO.java | 43 + .../entity/vo/rd/cluster/ClusterDetailVO.java | 77 + .../vo/rd/cluster/LogicalClusterVO.java | 128 + .../vo/rd/cluster/RdClusterMetricsVO.java | 111 + .../entity/vo/thirdpart/AppBasicInfoVO.java | 90 + .../events/ConsumerMetricsCollectedEvent.java | 23 + .../common/events/OrderApplyEvent.java | 13 + .../manager/common/events/OrderEvent.java | 28 + .../common/events/OrderPassedEvent.java | 16 + .../common/events/OrderRefusedEvent.java | 16 + .../events/TopicMetricsCollectedEvent.java | 30 + .../common/exception/ConfigException.java | 0 .../common/exception/CopyException.java | 0 .../kafka/manager/common/utils/CopyUtils.java | 2 +- .../kafka/manager/common/utils/DateUtils.java | 91 + .../common/utils/EasyApiLimitUtils.java | 69 + .../manager/common/utils/EncryptUtil.java | 5 +- .../kafka/manager/common/utils/HttpUtils.java | 242 + .../kafka/manager/common/utils/JsonUtils.java | 51 + .../manager/common}/utils/ListUtils.java | 18 +- .../kafka/manager/common/utils/NetUtils.java | 69 + .../manager/common/utils/NumberUtils.java | 30 + .../manager/common/utils/SpringTool.java | 56 +- .../kafka/manager/common/utils/UUIDUtils.java | 13 + .../manager/common/utils/ValidateUtils.java | 105 + .../utils/factory}/DefaultThreadFactory.java | 6 +- .../utils/factory/KafkaConsumerFactory.java | 63 + .../common/utils/jmx/JmxAttributeEnum.java | 52 + .../common/utils/jmx/JmxConnectorWrap.java | 137 + .../manager/common/utils/jmx/JmxConstant.java | 29 + .../kafka/manager/common/utils/jmx/Mbean.java | 0 .../common/utils/jmx/MbeanNameUtil.java | 79 + .../common/utils/jmx/MbeanNameUtilV2.java | 445 + .../manager/common/utils/jmx/MbeanV2.java | 69 + .../common/zookeeper}/ConfigClient.java | 2 +- .../common/zookeeper/StateChangeListener.java | 22 + .../common/zookeeper}/ZkConfigImpl.java | 3 +- .../manager/common/zookeeper/ZkPathUtil.java | 114 + .../zookeeper/znode}/ControllerData.java | 2 +- .../zookeeper/znode}/ReassignmentDTO.java | 2 +- .../zookeeper/znode/ReassignmentElemData.java | 4 +- .../zookeeper/znode/ReassignmentJsonData.java | 10 +- .../znode/brokers}/BrokerMetadata.java | 6 +- .../znode/brokers}/PartitionMap.java | 7 +- .../znode/brokers}/PartitionState.java | 4 +- .../znode/brokers}/TopicMetadata.java | 2 +- .../zookeeper/znode/config/ChangeData.java | 44 + .../znode/config/ConfigNodeData.java | 37 + .../znode/config/TopicQuotaData.java | 48 + .../znode/didi/JmxSwitchDataConstant.java | 15 + .../zookeeper/znode/didi/TopicJmxSwitch.java | 54 + .../package.json | 14 +- {console => kafka-manager-console}/pom.xml | 4 +- .../src/assets/image/admin.png | Bin .../src/assets/image/devops.png | Bin .../src/assets/image/images.d.ts | 0 .../src/assets/image/kafka-logo.png | Bin .../src/assets/image/kafka-manager.png | Bin .../src/assets/image/login-bg.png | Bin .../src/assets/image/logo.ico | Bin .../src/assets/image/normal.png | Bin .../src/assets/image/wechat.jpeg | Bin 0 -> 128319 bytes .../src/component/antd/index.tsx | 35 + .../src/component/chart/bar-chart.tsx | 90 + .../src/component/chart/date-picker-chart.tsx | 110 + .../src/component/chart/doughnut-chart.tsx | 60 + .../src/component/chart/index.less | 80 + .../src/component/chart/index.tsx | 4 + .../src/component/chart/line-chart.tsx | 55 + .../src/component/clipboard/index.tsx | 55 + .../src/component/expand-card/index.less | 39 + .../src/component/expand-card/index.tsx | 48 + .../src/component/flow-table/index.tsx | 39 +- .../src/component/virtual-scroll-select.tsx | 136 + .../src/component/x-form-wrapper/index.tsx | 156 + .../src/component/x-form/index.less | 11 + .../src/component/x-form/index.tsx | 197 + .../src/constants/left-menu.ts | 80 + .../src/constants/status-map.ts | 209 + .../src/constants/strategy.ts | 74 + kafka-manager-console/src/constants/table.ts | 35 + .../src/container/admin/admin-app-list.tsx | 47 + .../src/container/admin/bill-detail.tsx | 103 + .../admin/bill-management/index.less | 5 + .../container/admin/bill-management/index.tsx | 20 + .../admin/bill-management/personal-bill.tsx | 128 + .../admin/broker-detail/base-info.tsx | 121 + .../admin/broker-detail/disk-info.tsx | 172 + .../container/admin}/broker-detail/index.less | 109 +- .../container/admin/broker-detail/index.tsx | 67 + .../admin/broker-detail/monitor-info.tsx | 65 + .../admin/broker-detail/partition-info.tsx | 104 + .../admin/broker-detail/topic-analysis.tsx | 117 + .../admin/broker-detail/topic-info.tsx | 127 + .../admin/cluster-detail/cluster-broker.tsx | 259 + .../admin/cluster-detail/cluster-consumer.tsx | 131 + .../cluster-detail/cluster-controller.tsx | 97 + .../admin/cluster-detail/cluster-overview.tsx | 141 + .../admin/cluster-detail/cluster-topic.tsx | 217 + .../admin/cluster-detail/current-limiting.tsx | 97 + .../cluster-detail/exclusive-cluster.tsx | 291 + .../container/admin/cluster-detail/index.less | 84 + .../container/admin/cluster-detail/index.tsx | 73 + .../admin/cluster-detail/logical-cluster.tsx | 169 + .../container/admin/cluster-list/index.less | 0 .../container/admin/cluster-list/index.tsx | 318 + .../src/container/admin/config.tsx | 319 + .../container/admin/configure-management.tsx | 74 + .../src/container/admin/data-curve/config.ts | 210 + .../src/container/admin/data-curve/index.less | 14 + .../src/container/admin/data-curve/index.tsx | 49 + .../src/container/admin/data-curve/parser.ts | 147 + .../src/container/admin/index.tsx | 13 + .../src/container/admin/individual-bill.tsx | 159 + .../admin/operation-detail/essential-info.tsx | 82 + .../admin/operation-detail/index.less | 26 + .../admin/operation-detail/index.tsx | 128 + .../operation-detail/taskStatus-details.tsx | 211 + .../operation-management/cluster-task.tsx | 172 + .../admin/operation-management/config.tsx | 59 + .../admin/operation-management/index.less | 7 + .../admin/operation-management/index.tsx | 46 + .../operation-management/migration-detail.tsx | 226 + .../operation-management/migration-task.tsx | 110 + .../container/admin/platform-management.tsx | 30 + .../src/container/admin/user-management.tsx | 88 + .../container/admin/version-management.tsx | 105 + .../container/alarm/add-alarm/action-form.tsx | 57 + .../alarm/add-alarm/alarm-select.tsx | 60 + .../src/container/alarm/add-alarm/config.tsx | 246 + .../container/alarm/add-alarm/filter-form.tsx | 391 + .../src/container/alarm/add-alarm/index.less | 224 + .../src/container/alarm/add-alarm/index.tsx | 171 + .../alarm/add-alarm/strategy-form.tsx | 369 + .../container/alarm/add-alarm/time-form.tsx | 137 + .../container/alarm/add-alarm/type-form.tsx | 74 + .../alarm/alarm-detail/alarm-history.tsx | 103 + .../alarm/alarm-detail/history-detail.tsx | 141 + .../container/alarm/alarm-detail/index.less | 64 + .../container/alarm/alarm-detail/index.tsx | 64 + .../alarm/alarm-detail/shield-history.tsx | 180 + .../src/container/alarm/alarm-list.tsx | 87 + .../src/container/alarm/index.tsx | 2 + .../src/container/app-select.tsx | 46 + .../src/container/app/app-detail.tsx | 205 + .../src/container/app/app-list.tsx | 136 + .../src/container/app/index.less | 38 + .../src/container/app/index.tsx | 2 + .../cluster/cluster-detail/cluster-broker.tsx | 159 + .../cluster-detail/cluster-overview.tsx | 140 + .../cluster/cluster-detail/cluster-topic.tsx | 152 + .../cluster-detail/current-limiting.tsx | 102 + .../cluster/cluster-detail/index.less | 63 + .../cluster/cluster-detail/index.tsx | 56 + .../src/container/cluster/config.tsx | 95 + .../src/container/cluster/index.less | 24 + .../src/container/cluster/index.tsx | 2 + .../src/container/cluster/my-cluster.tsx | 254 + .../src/container/common-curve/config.ts | 85 + .../src/container/common-curve/index.less | 27 + .../src/container/common-curve/index.tsx | 118 + .../src/container/configure-info.tsx | 30 + .../src/container/custom-component.tsx | 33 + .../src/container/drawer/add-alarm.tsx | 10 + .../src/container/drawer/data-migration.tsx | 329 + .../src/container/error/forbidden.tsx | 14 + .../src/container/error/index.less | 7 + .../src/container/error/index.tsx | 1 + .../src/container/expert/diagnosis/index.less | 0 .../src/container/expert/diagnosis/index.tsx | 98 + .../src/container/expert/index.tsx | 4 + .../expert/topic-governance/index.less | 19 + .../expert/topic-governance/index.tsx | 222 + .../container/expert/topic-hotspot/index.less | 23 + .../container/expert/topic-hotspot/index.tsx | 186 + .../topic-partition/batch-expansion.tsx | 122 + .../expert/topic-partition/index.less | 31 + .../expert/topic-partition/index.tsx | 157 + .../src/container/full-screen/index.less | 18 + .../src/container/full-screen/index.tsx | 23 + .../src/container/header/index.less | 162 + .../src/container/header/index.tsx | 187 + .../src/container/left-menu/index.less | 15 +- .../src/container/left-menu/index.tsx | 98 + .../src/container/modal/admin/cluster.ts | 277 + .../modal/admin/expand-partition.tsx | 149 + .../src/container/modal/admin/index.ts | 5 + .../modal/admin/leader-rebalance.tsx | 186 + .../src/container/modal/admin/migration.ts | 303 + .../src/container/modal/admin/task.ts | 277 + .../src/container/modal/admin/user.ts | 46 + .../src/container/modal/admin/version.ts | 191 + .../src/container/modal/alarm.tsx | 80 + .../src/container/modal/app.tsx | 127 + .../modal/cancel-topic-permission.tsx | 181 + .../src/container/modal/cluster.tsx | 58 + .../container/modal/connect-topic-list.tsx | 81 + .../src/container/modal/expert.tsx | 33 + .../src/container/modal/index.tsx | 5 + .../src/container/modal/offline-app-modal.tsx | 77 + .../container/modal/offline-cluster-modal.tsx | 95 + .../src/container/modal/order.tsx | 353 + .../modal/render-order-op-result.tsx | 81 + .../src/container/modal/topic.tsx | 753 ++ .../src/container/network-flow.tsx | 87 + .../src/container/search-filter.tsx | 204 + .../src/container/staff-select.tsx | 108 + .../src/container/topic/config.tsx | 337 + .../src/container/topic/index.less | 58 + .../src/container/topic/index.tsx | 4 + .../src/container/topic/peak-flow.tsx | 39 + .../src/container/topic/topic-all.tsx | 111 + .../src/container/topic/topic-app-list.tsx | 61 + .../src/container/topic/topic-app-select.tsx | 61 + .../topic/topic-detail/appid-information.tsx | 140 + .../topic/topic-detail/base-information.tsx | 245 + .../topic/topic-detail/bill-information.tsx | 118 + .../topic-detail/brokers-information.tsx | 163 + .../topic/topic-detail/common-detail.tsx | 98 + .../topic-detail/connect-information.tsx | 112 + .../container/topic/topic-detail/group-id.tsx | 264 + .../container/topic/topic-detail/index.less | 217 + .../container/topic/topic-detail/index.tsx | 380 + .../topic-detail/partition-information.tsx | 132 + .../topic/topic-detail/reset-offset.tsx | 173 + .../topic/topic-detail/status-chart.tsx | 78 + .../src/container/topic/topic-mine.tsx | 170 + .../container/user-center/bill-detaill.tsx | 103 + .../src/container/user-center/config.tsx | 245 + .../src/container/user-center/index.less | 108 + .../src/container/user-center/index.tsx | 4 + .../src/container/user-center/my-approval.tsx | 88 + .../src/container/user-center/my-bill.tsx | 158 + .../src/container/user-center/my-order.tsx | 38 + .../container/user-center/order-detail.tsx | 266 + .../src/container/user-center/order-list.tsx | 192 + .../src/container/wrapper/custom-modal.tsx | 36 + .../src/container/wrapper}/index.less | 19 +- .../src/container/wrapper/index.tsx | 29 + kafka-manager-console/src/lib/api-cache.ts | 32 + kafka-manager-console/src/lib/api.ts | 884 ++ .../src/lib/bar-pie-config.ts | 91 + kafka-manager-console/src/lib/chart-utils.ts | 111 + kafka-manager-console/src/lib/fetch.ts | 133 + .../src/lib/line-charts-config.ts | 414 + .../src/lib/local-storage.ts | 37 + .../src/lib/url-parser.ts | 1 - kafka-manager-console/src/lib/utils.ts | 199 + .../src/routers/index.htm | 2 + .../src/routers/index.tsx | 2 - .../src/routers/page/admin.tsx | 72 + .../src/routers/page/alarm.tsx | 39 + .../src/routers/page/cluster.tsx | 23 + .../src/routers/page/common.tsx | 57 + .../src/routers/page/error.tsx | 22 + .../src/routers/page/expert.tsx | 39 + .../src/routers/page}/index.less | 21 +- .../src/routers/page/info.tsx | 22 + .../src/routers/page/login/index.less | 0 .../src/routers/page/login/index.tsx | 6 +- .../src/routers/page/login/sso-callback.tsx | 33 + .../src/routers/page/topic.tsx | 49 + .../src/routers/page/user.tsx | 38 + kafka-manager-console/src/routers/router.tsx | 71 + .../src/store/admin-monitor.ts | 67 + kafka-manager-console/src/store/admin.ts | 780 ++ kafka-manager-console/src/store/alarm.ts | 190 + kafka-manager-console/src/store/app.ts | 185 + kafka-manager-console/src/store/bill.ts | 57 + kafka-manager-console/src/store/cluster.ts | 285 + .../src/store/consume.ts | 7 +- kafka-manager-console/src/store/curve-info.ts | 75 + kafka-manager-console/src/store/expert.ts | 178 + .../src/store/full-screen.ts | 19 + .../src/store/index.ts | 4 +- kafka-manager-console/src/store/modal.ts | 59 + kafka-manager-console/src/store/order.ts | 193 + kafka-manager-console/src/store/region.ts | 50 + kafka-manager-console/src/store/time.ts | 29 + kafka-manager-console/src/store/topic.ts | 574 + .../src/store/url-query.ts | 1 + kafka-manager-console/src/store/users.ts | 67 + kafka-manager-console/src/store/version.ts | 133 + kafka-manager-console/src/store/wrapper.ts | 39 + .../src/styles/custom-component.less | 23 + .../src/styles/header-search.less | 40 + .../src/styles/search-filter.less | 26 + .../src/styles/table-filter.less | 34 + .../src/styles/theme-dark.less | 3 + kafka-manager-console/src/types/alarm.ts | 76 + kafka-manager-console/src/types/base-type.ts | 1123 ++ .../tsconfig.json | 0 .../tslint.json | 3 +- .../webpack.config.js | 19 +- {service => kafka-manager-core}/pom.xml | 45 +- .../service/cache/ConsumerMetadataCache.java | 48 +- .../service/cache/KafkaClientPool.java | 186 + .../service/cache/KafkaMetricsCache.java | 45 + .../cache/LogicalClusterMetadataManager.java | 196 + .../cache/PhysicalClusterMetadataManager.java | 494 + .../manager/service/cache/ThreadPool.java | 37 + .../manager/service/service/AdminService.java | 37 + .../service/service/AnalysisService.java | 2 +- .../service/service/BrokerService.java | 67 + .../service/service/ClusterService.java | 47 + .../service/service/ConfigService.java | 37 + .../service/service/ConsumerService.java | 55 + .../service/service/ExpertService.java | 45 + .../manager/service/service/JmxService.java | 58 + .../service/service/KafkaBillService.java | 22 + .../service/LogicalClusterService.java | 73 + .../service/service/OperateRecordService.java | 16 + .../service/service/ReassignService.java | 41 + .../service/service/RegionService.java | 76 + .../service/service/ThrottleService.java | 48 + .../service/service/TopicExpiredService.java | 16 + .../service/service/TopicManagerService.java | 102 + .../manager/service/service/TopicService.java | 108 + .../service/service/ZookeeperService.java | 13 + .../service/service/gateway/AppService.java | 70 + .../service/gateway/AuthorityService.java | 63 + .../service/gateway/GatewayConfigService.java | 18 + .../service/service/gateway/QuotaService.java | 37 + .../service/gateway/SecurityService.java | 16 + .../gateway/TopicConnectionService.java | 56 + .../service/gateway/TopicReportService.java | 13 + .../service/gateway/impl/AppServiceImpl.java | 245 + .../gateway/impl/AuthorityServiceImpl.java | 195 + .../impl/GatewayConfigServiceImpl.java | 155 + .../gateway/impl/QuotaServiceImpl.java | 81 + .../gateway/impl/SecurityServiceImpl.java | 35 + .../impl/TopicConnectionServiceImpl.java | 224 + .../gateway/impl/TopicReportServiceImpl.java | 24 + .../service/impl/AdminServiceImpl.java | 305 + .../service/impl/AnalysisServiceImpl.java | 89 +- .../service/impl/BrokerServiceImpl.java | 404 + .../service/impl/ClusterServiceImpl.java | 304 + .../service/impl/ConfigServiceImpl.java | 238 + .../service/impl/ConsumerServiceImpl.java | 289 +- .../service/impl/ExpertServiceImpl.java | 252 + .../service/service/impl/JmxServiceImpl.java | 490 + .../service/impl/KafkaBillServiceImpl.java | 75 + .../impl/LogicalClusterServiceImpl.java | 354 + .../impl/OperateRecordServiceImpl.java | 38 + .../service/impl/ReassignServiceImpl.java | 337 + .../service/impl/RegionServiceImpl.java | 330 + .../service/impl/ThrottleServiceImpl.java | 111 + .../service/impl/TopicExpiredServiceImpl.java | 78 + .../service/impl/TopicManagerServiceImpl.java | 546 + .../service/impl/TopicServiceImpl.java | 866 ++ .../service/impl/ZookeeperServiceImpl.java | 43 + .../AbstractAllocateQuotaStrategy.java | 11 + .../strategy/AbstractHealthScoreStrategy.java | 16 + .../healthscore/DidiHealthScoreStrategy.java | 149 + .../quota/BaseAllocateQuotaStrategy.java | 19 + .../manager/service/utils/ConfigUtils.java | 34 + .../service/utils/KafkaZookeeperUtils.java | 201 + .../service/utils/MetricsConvertUtils.java | 203 + .../manager/service/utils/TopicCommands.java | 201 + .../service/utils/TopicReassignUtils.java | 105 + .../zookeeper/BrokerStateListener.java | 89 + .../zookeeper/ControllerStateListener.java | 83 + .../service/zookeeper/TopicStateListener.java | 110 + .../src/test/java/META-INF/MANIFEST.MF | 0 .../kafka/manager/service/FutureTest.java | 0 .../manager/service/utils/SpringTestBase.java | 0 {dao => kafka-manager-dao}/pom.xml | 16 +- .../kafka/manager/dao/AccountDao.java | 7 +- .../kafka/manager/dao/BrokerDao.java | 6 +- .../kafka/manager/dao/BrokerMetricsDao.java | 7 +- .../kafka/manager/dao/ClusterDao.java | 4 +- .../kafka/manager/dao/ClusterMetricsDao.java | 4 +- .../kafka/manager/dao/ClusterTaskDao.java | 21 + .../kafka/manager/dao/ConfigDao.java | 21 + .../kafka/manager/dao/ControllerDao.java | 2 +- .../kafka/manager/dao/HeartbeatDao.java | 16 + .../kafka/manager/dao/KafkaBillDao.java | 22 + .../kafka/manager/dao/KafkaFileDao.java | 23 + .../kafka/manager/dao/LogicalClusterDao.java | 23 + .../kafka/manager/dao/MonitorRuleDao.java | 23 + .../kafka/manager/dao/OperateRecordDao.java | 18 + .../kafka/manager/dao/OrderDao.java | 89 + .../kafka/manager/dao/ReassignTaskDao.java | 61 + .../kafka/manager/dao/RegionDao.java | 4 +- .../kafka/manager/dao/TopicAppMetricsDao.java | 34 + .../kafka/manager/dao/TopicDao.java | 12 +- .../kafka/manager/dao/TopicExpiredDao.java | 20 + .../kafka/manager/dao/TopicMetricsDao.java | 8 +- .../manager/dao/TopicRequestMetricsDao.java | 41 + .../kafka/manager/dao/TopicStatisticsDao.java | 29 + .../manager/dao/TopicThrottledMetricsDao.java | 34 + .../kafka/manager/dao/gateway/AppDao.java | 65 + .../manager/dao/gateway/AuthorityDao.java | 40 + .../manager/dao/gateway/GatewayConfigDao.java | 15 + .../manager/dao/gateway/KafkaAclDao.java | 23 + .../manager/dao/gateway/KafkaUserDao.java | 27 + .../dao/gateway/TopicConnectionDao.java | 21 + .../manager/dao/gateway/TopicReportDao.java | 15 + .../manager/dao/gateway/impl/AppDaoImpl.java | 94 + .../dao/gateway/impl/AuthorityDaoImpl.java | 115 + .../gateway/impl/GatewayConfigDaoImpl.java | 38 + .../dao/gateway/impl/KafkaAclDaoImpl.java | 41 + .../dao/gateway/impl/KafkaUserDaoImpl.java | 40 + .../gateway/impl/TopicConnectionDaoImpl.java | 78 + .../dao/gateway/impl/TopicReportDaoImpl.java | 39 + .../manager/dao/impl/AccountDaoImpl.java | 20 +- .../kafka/manager/dao/impl/BrokerDaoImpl.java | 22 +- .../manager/dao/impl/BrokerMetricsImpl.java | 15 +- .../manager/dao/impl/ClusterDaoImpl.java | 14 +- .../dao/impl/ClusterMetricsDaoImpl.java | 8 +- .../manager/dao/impl/ClusterTaskDaoImpl.java | 53 + .../kafka/manager/dao/impl/ConfigDaoImpl.java | 48 + .../manager/dao/impl/ControllerDaoImpl.java | 2 +- .../manager/dao/impl/HeartbeatDaoImpl.java | 34 + .../manager/dao/impl/KafkaBillDaoImpl.java | 63 + .../manager/dao/impl/KafkaFileDaoImpl.java | 53 + .../dao/impl/LogicalClusterDaoImpl.java | 53 + .../manager/dao/impl/MonitorRuleDaoImpl.java | 60 + .../dao/impl/OperateRecordDaoImpl.java | 42 + .../kafka/manager/dao/impl/OrderDaoImpl.java | 98 + .../manager/dao/impl/ReassignTaskDaoImpl.java | 64 + .../kafka/manager/dao/impl/RegionDaoImpl.java | 13 +- .../dao/impl/TopicAppMetricsDaoImpl.java | 52 + .../kafka/manager/dao/impl/TopicDaoImpl.java | 115 + .../manager/dao/impl/TopicExpiredDaoImpl.java | 53 + .../manager/dao/impl/TopicMetricsDaoImpl.java | 66 + .../dao/impl/TopicRequestMetricsDaoImpl.java | 64 + .../dao/impl/TopicStatisticsDaoImpl.java | 76 + .../impl/TopicThrottledMetricsDaoImpl.java | 76 + .../kafka/manager/vfs/SpringBootVFS.java | 0 .../src/main/resources/mapper/AccountDao.xml | 54 + .../src/main/resources/mapper/AppDao.xml | 65 + .../main/resources/mapper/AuthorityDao.xml | 48 + .../src/main/resources/mapper/BrokerDao.xml | 39 + .../resources/mapper/BrokerMetricsDao.xml | 37 + .../src/main/resources/mapper/ClusterDao.xml | 51 + .../resources/mapper/ClusterMetricsDao.xml | 35 + .../main/resources/mapper/ClusterTaskDao.xml | 83 + .../src/main/resources/mapper/ConfigDao.xml | 41 + .../main/resources/mapper/ControllerDao.xml | 18 +- .../resources/mapper/GatewayConfigDao.xml | 22 + .../main/resources/mapper/HeartbeatDao.xml | 20 + .../src/main/resources/mapper/KafkaAclDao.xml | 29 + .../main/resources/mapper/KafkaBillDao.xml | 56 + .../main/resources/mapper/KafkaFileDao.xml | 60 + .../main/resources/mapper/KafkaUserDao.xml | 29 + .../resources/mapper/LogicalClusterDao.xml | 52 + .../main/resources/mapper/MonitorRuleDao.xml | 53 + .../resources/mapper/OperateRecordDao.xml | 51 + .../src/main/resources/mapper/OrderDao.xml | 111 + .../main/resources/mapper/ReassignTaskDao.xml | 93 + .../src/main/resources/mapper/RegionDao.xml | 65 + .../resources/mapper/TopicAppMetricsDao.xml | 38 + .../resources/mapper/TopicConnectionDao.xml | 53 + .../src/main/resources/mapper/TopicDao.xml | 64 + .../main/resources/mapper/TopicExpiredDao.xml | 39 + .../main/resources/mapper/TopicMetricsDao.xml | 43 + .../main/resources/mapper/TopicReportDao.xml | 48 + .../mapper/TopicRequestMetricsDao.xml | 54 + .../resources/mapper/TopicStatisticsDao.xml | 62 + .../mapper/TopicThrottledMetricsDao.xml | 57 + .../mapper/gateway/DeprecatedKafkaAclDao.xml | 28 + .../mapper/gateway/DeprecatedKafkaUserDao.xml | 29 + .../src/main/resources/mybatis-config.xml | 2 +- .../kafka-manager-account/pom.xml | 42 + .../kafka/manager/account/AccountService.java | 36 + .../kafka/manager/account/LoginService.java | 19 + .../account/common/EnterpriseStaff.java | 53 + .../AbstractEnterpriseStaffService.java | 16 + .../component/AbstractSingleSignOn.java | 28 + .../account/BaseEnterpriseStaffService.java | 58 + .../component/sso/BaseSessionSignOn.java | 63 + .../account/impl/AccountServiceImpl.java | 272 + .../account/impl/LoginServiceImpl.java | 109 + .../kafka-manager-bpm/pom.xml | 38 + .../kafka/manager/bpm/BpmService.java | 10 + .../kafka/manager/bpm/Converts.java | 25 + .../kafka/manager/bpm/OrderService.java | 103 + .../kafka/manager/bpm/common/OrderResult.java | 41 + .../manager/bpm/common}/OrderStatusEnum.java | 7 +- .../manager/bpm/common/OrderTypeEnum.java | 61 + .../bpm/common/entry/BaseOrderDetailData.java | 141 + .../bpm/common/entry/apply/OrderDTO.java | 76 + .../apply/OrderExtensionApplyAppDTO.java | 57 + .../apply/OrderExtensionApplyClusterDTO.java | 76 + .../apply/OrderExtensionApplyTopicDTO.java | 184 + .../apply/OrderExtensionAuthorityDTO.java | 80 + .../apply/OrderExtensionDeleteAppDTO.java | 33 + .../apply/OrderExtensionDeleteClusterDTO.java | 33 + .../apply/OrderExtensionDeleteTopicDTO.java | 45 + .../apply/OrderExtensionModifyClusterDTO.java | 33 + .../entry/apply/OrderExtensionQuotaDTO.java | 128 + .../apply/PartitionOrderExtensionDTO.java | 70 + .../entry/detail/AbstractOrderDetailData.java | 8 + .../entry/detail/OrderDetailApplyAppDTO.java | 57 + .../detail/OrderDetailApplyAuthorityDTO.java | 90 + .../detail/OrderDetailApplyClusterDTO.java | 57 + .../detail/OrderDetailApplyTopicDTO.java | 125 + .../entry/detail/OrderDetailDeleteAppDTO.java | 72 + .../detail/OrderDetailDeleteAuthorityDTO.java | 127 + .../detail/OrderDetailDeleteClusterDTO.java | 70 + .../detail/OrderDetailDeleteTopicDTO.java | 116 + .../detail/OrderDetailModifyClusterDTO.java | 57 + .../detail/PartitionOrderDetailData.java | 147 + .../entry/detail/QuotaOrderDetailData.java | 213 + .../bpm/common/handle/OrderHandleBaseDTO.java | 75 + .../common/handle/OrderHandleBatchDTO.java | 65 + .../common/handle/OrderHandleQuotaDTO.java | 69 + .../common/handle/OrderHandleTopicDTO.java | 95 + .../AbstractOrderStorageService.java | 37 + .../bpm/component/LocalStorageService.java | 146 + .../manager/bpm/impl/OrderServiceImpl.java | 287 + .../manager/bpm/order/AbstractAppOrder.java | 31 + .../bpm/order/AbstractAuthorityOrder.java | 54 + .../bpm/order/AbstractClusterOrder.java | 32 + .../manager/bpm/order/AbstractOrder.java | 148 + .../manager/bpm/order/AbstractTopicOrder.java | 31 + .../manager/bpm/order/impl/ApplyAppOrder.java | 92 + .../bpm/order/impl/ApplyAuthorityOrder.java | 161 + .../bpm/order/impl/ApplyClusterOrder.java | 68 + .../bpm/order/impl/ApplyPartitionOrder.java | 209 + .../bpm/order/impl/ApplyQuotaOrder.java | 249 + .../bpm/order/impl/ApplyTopicOrder.java | 173 + .../bpm/order/impl/DeleteAppOrder.java | 105 + .../bpm/order/impl/DeleteAuthorityOrder.java | 129 + .../bpm/order/impl/DeleteClusterOrder.java | 85 + .../bpm/order/impl/DeleteTopicOrder.java | 148 + .../bpm/order/impl/ModifyClusterOrder.java | 71 + .../kafka-manager-kcm/pom.xml | 57 + .../kafka/manager/kcm/ClusterTaskService.java | 32 + .../kafka/manager/kcm/KafkaFileService.java | 30 + .../kafka/manager/kcm/common/Converters.java | 49 + .../common/bizenum/ClusterTaskActionEnum.java | 39 + .../common/bizenum/ClusterTaskStateEnum.java | 47 + .../bizenum/ClusterTaskSubStateEnum.java | 53 + .../common/bizenum/ClusterTaskTypeEnum.java | 110 + .../kcm/common/entry/ClusterTaskConstant.java | 23 + .../common/entry/ao/ClusterTaskStatus.java | 84 + .../common/entry/ao/ClusterTaskSubStatus.java | 62 + .../kcm/common/entry/ao/CreationTaskData.java | 136 + .../entry/dto/AbstractClusterTaskDTO.java | 143 + .../common/entry/dto/ClusterHostTaskDTO.java | 54 + .../common/entry/dto/ClusterRoleTaskDTO.java | 53 + .../entry/dto/ClusterTaskActionDTO.java | 64 + .../kcm/component/agent/AbstractAgent.java | 45 + .../manager/kcm/component/agent/n9e/N9e.java | 225 + .../component/agent/n9e/entry/N9eResult.java | 35 + .../agent/n9e/entry/N9eTaskResultDTO.java | 187 + .../agent/n9e/entry/N9eTaskStatusEnum.java | 59 + .../agent/n9e/entry/N9eTaskStdoutDTO.java | 35 + .../storage/AbstractStorageService.java | 25 + .../component/storage/common/StorageEnum.java | 38 + .../kcm/component/storage/local/Local.java | 29 + .../kcm/impl/ClusterTaskServiceImpl.java | 310 + .../kcm/impl/KafkaFileServiceImpl.java | 180 + .../kcm/tasks/AbstractClusterTaskService.java | 39 + .../kcm/tasks/ClusterHostTaskService.java | 34 + .../kcm/tasks/ClusterRoleTaskService.java | 96 + .../main/resources/application-kcm-dev.yml | 7 + .../kafka-manager-monitor/pom.xml | 56 + .../kafka/manager/monitor/MonitorService.java | 50 + .../monitor/common/MonitorSinkConstant.java | 26 + .../manager/monitor/common/entry/Alert.java | 214 + .../manager/monitor/common/entry/Metric.java | 83 + .../monitor/common/entry/MetricSinkPoint.java | 80 + .../monitor/common/entry/NotifyGroup.java | 46 + .../manager/monitor/common/entry/Silence.java | 80 + .../monitor/common/entry/Strategy.java | 133 + .../monitor/common/entry/StrategyAction.java | 54 + .../common/entry/StrategyExpression.java | 79 + .../monitor/common/entry/StrategyFilter.java | 57 + .../entry/bizenum/MonitorMetricNameEnum.java | 61 + .../monitor/common/entry/dto/MetricPoint.java | 35 + .../common/entry/dto/MonitorRuleDTO.java | 161 + .../common/entry/dto/MonitorSilenceDTO.java | 90 + .../entry/dto/MonitorStrategyActionDTO.java | 67 + .../dto/MonitorStrategyExpressionDTO.java | 91 + .../entry/dto/MonitorStrategyFilterDTO.java | 67 + .../common/entry/sink/MonitorBaseSinkTag.java | 31 + .../sink/MonitorConsumePartitionSinkTag.java | 33 + .../entry/sink/MonitorConsumerSinkTag.java | 43 + .../entry/sink/MonitorKafkaBaseSinkTag.java | 30 + .../sink/MonitorTopicPartitionSinkTag.java | 43 + .../entry/sink/MonitorTopicSinkTag.java | 32 + .../sink/MonitorTopicThrottledSinkTag.java | 43 + .../common/entry/vo/MonitorAlertDetailVO.java | 38 + .../common/entry/vo/MonitorAlertVO.java | 164 + .../common/entry/vo/MonitorMetricPoint.java | 40 + .../common/entry/vo/MonitorMetricVO.java | 81 + .../common/entry/vo/MonitorNotifyGroupVO.java | 49 + .../common/entry/vo/MonitorRuleDetailVO.java | 103 + .../common/entry/vo/MonitorRuleSummaryVO.java | 101 + .../common/entry/vo/MonitorSilenceVO.java | 89 + .../common/monitor/MonitorAlertDetail.java | 43 + .../common/monitor/MonitorRuleSummary.java | 90 + .../monitor/common/utils/CommonConverter.java | 105 + .../component/AbstractMonitorService.java | 57 + .../monitor/component/n9e/N9eConverter.java | 30 + .../monitor/component/n9e/N9eService.java | 166 + .../n9e/entry/N9eMetricSinkPoint.java | 113 + .../component/n9e/entry/N9eResult.java | 35 + .../monitor/impl/MonitorServiceImpl.java | 290 + .../resources/application-monitor-dev.yml | 3 + .../kafka-manager-notify/pom.xml | 37 + .../notify/OrderApplyNotifyService.java | 43 + .../notify/OrderPassedNotifyService.java | 36 + .../notify/OrderRefusedNotifyService.java | 36 + .../manager/notify/common/NotifyConstant.java | 18 + .../notify/common/OrderNotifyTemplate.java | 43 + .../notifyer/AbstractNotifyService.java | 5 + .../notify/notifyer/KafkaNotifierService.java | 24 + .../main/resources/application-notify-dev.yml | 8 + .../kafka-manager-openapi/pom.xml | 35 + kafka-manager-task/pom.xml | 45 + .../manager/task/common/BaseTaskEvent.java | 20 + .../TopicThrottledMetricsCollectedEvent.java | 24 + .../task/component/AbstractScheduledTask.java | 184 + .../manager/task/component/BaseBizTask.java | 35 + .../task/component/CustomScheduled.java | 21 + .../manager/task/component/EmptyEntry.java | 30 + .../manager/task/component/Heartbeat.java | 38 + .../task/component/ScheduledTaskConstant.java | 26 + .../task/config/RegionCapacityConfig.java | 71 + .../manager/task/config/TopicBillConfig.java | 58 + .../task/dispatch/biz/CalKafkaTopicBill.java | 132 + .../task/dispatch/biz/CalRegionCapacity.java | 84 + .../task/dispatch/biz/CalTopicStatistics.java | 96 + .../task/dispatch/biz/FlushBrokerTable.java | 115 + .../task/dispatch/biz/FlushExpiredTopic.java | 128 + .../dispatch/biz/SyncClusterTaskState.java | 62 + .../collect/CollectAndPublishCGData.java | 172 + ...ollectAndPublishTopicThrottledMetrics.java | 50 + .../metrics/delete/DeleteMetrics.java | 117 + .../SinkCommunityTopicMetrics2Monitor.java | 132 + .../metrics/store/StoreBrokerMetrics.java | 134 + .../store/StoreCommunityTopicMetrics.java | 52 + .../store/StoreDiDiAppTopicMetrics.java | 70 + .../StoreDiDiTopicRequestTimeMetrics.java | 74 + .../dispatch/op/AutoHandleTopicOrder.java | 192 + .../dispatch/op/AutomatedHandleOrder.java | 117 + .../task/dispatch/op/FlushReassignment.java | 252 + .../SinkCommunityTopicMetrics2Kafka.java | 82 + .../listener/SinkConsumerMetrics2Kafka.java | 94 + .../listener/SinkConsumerMetrics2Monitor.java | 171 + .../SinkTopicThrottledMetrics2Monitor.java | 110 + .../StoreCommunityTopicMetrics2DB.java | 55 + .../StoreTopicThrottledMetrics2DB.java | 86 + .../task/schedule/FlushTopicMetrics.java | 58 + .../FlushBKConsumerGroupMetadata.java | 107 +- .../metadata/FlushClusterMetadata.java | 51 + .../metadata/FlushTopicRetentionTime.java | 63 + .../FlushZKConsumerGroupMetadata.java | 121 + {web => kafka-manager-web}/pom.xml | 126 +- .../kafka/manager/web/MainApplication.java | 17 +- .../manager/web/api/HealthController.java | 29 + .../web/api/versionone/LoginController.java | 85 + .../gateway/GatewayHeartbeatController.java | 52 + .../gateway/GatewayReportController.java | 49 + .../gateway/GatewaySecurityController.java | 93 + .../GatewayServiceDiscoveryController.java | 174 + .../normal/NormalAccountController.java | 58 + .../normal/NormalAppController.java | 160 + .../normal/NormalBillController.java | 106 + .../normal/NormalClusterController.java | 204 + .../normal/NormalConfigController.java | 72 + .../normal/NormalConsumerController.java | 184 + .../normal/NormalJmxController.java | 51 + .../normal/NormalMonitorController.java | 222 + .../normal/NormalOrderController.java | 125 + .../normal/NormalTopicController.java | 322 + .../normal/NormalTopicMineController.java | 109 + .../versionone/op/OpClusterController.java | 72 + .../op/OpClusterTaskController.java | 148 + .../api/versionone/op/OpExpertController.java | 66 + .../versionone/op/OpReassignController.java | 104 + .../api/versionone/op/OpUtilsController.java | 222 + .../versionone/rd/RdAccountController.java | 77 + .../api/versionone/rd/RdAppController.java | 43 + .../api/versionone/rd/RdBillController.java | 136 + .../api/versionone/rd/RdBrokerController.java | 185 + .../versionone/rd/RdClusterController.java | 171 + .../api/versionone/rd/RdConfigController.java | 70 + .../versionone/rd/RdConsumerController.java | 62 + .../versionone/rd/RdKafkaFileController.java | 79 + .../rd/RdLogicalClusterController.java | 81 + .../api/versionone/rd/RdNotifyController.java | 33 + .../rd/RdOperateRecordController.java | 46 + .../api/versionone/rd/RdRegionController.java | 62 + .../versionone/rd/RdScheduledController.java | 65 + .../api/versionone/rd/RdTopicController.java | 75 + .../manager/web/config/DataSourceConfig.java | 0 .../manager/web/config/SwaggerConfig.java | 8 +- .../manager/web/config/WebMvcConfig.java | 8 +- .../web/converters/AccountConverter.java | 37 + .../manager/web/converters/AppConverter.java | 70 + .../web/converters/BrokerModelConverter.java | 191 + .../web/converters/ClusterModelConverter.java | 252 + .../converters/ClusterTaskModelConverter.java | 116 + .../web/converters/CommonModelConverter.java | 131 + .../web/converters/ConfigConverter.java | 33 + .../converters/ConsumerModelConverter.java | 43 +- .../web/converters/ExpertConverter.java | 108 + .../web/converters/GatewayModelConverter.java | 52 + .../web/converters/KafkaFileConverter.java | 37 + .../LogicalClusterModelConverter.java | 56 + .../web/converters/MonitorRuleConverter.java | 139 + .../OperateRecordModelConverter.java | 32 + .../web/converters/OrderConverter.java | 88 + .../converters/ReassignModelConverter.java | 145 + .../web/converters/RegionModelConverter.java | 57 + .../web/converters/TopicMineConverter.java | 75 + .../web/converters/TopicModelConverter.java | 223 + .../web/inteceptor/PermissionInterceptor.java | 33 + .../web/inteceptor/WebMetricsInterceptor.java | 137 + .../manager/web/metrics/MetricsRegistry.java | 88 + .../kafka/manager/web/utils/ResultCache.java | 25 + .../src/main/resources/application.yml | 52 + .../kafka-manager-springboot-distribution.xml | 0 .../src/main/resources/logback-spring.xml | 31 +- pom.xml | 94 +- .../service/cache/ClusterMetadataManager.java | 385 - .../service/cache/KafkaClientCache.java | 213 - .../service/cache/KafkaMetricsCache.java | 87 - .../service/collector/BaseCollectTask.java | 33 - .../collector/CollectBrokerMetricsTask.java | 49 - .../CollectConsumerGroupZKMetadataTask.java | 67 - .../collector/CollectConsumerMetricsTask.java | 74 - .../collector/CollectTopicMetricsTask.java | 44 - .../monitor/AbstractMonitorMatchService.java | 26 - .../service/monitor/AlarmNotifyService.java | 52 - .../service/monitor/AlarmRuleManager.java | 145 - .../monitor/AlarmScheduleCheckTask.java | 131 - .../impl/BrokerMonitorMatchServiceImpl.java | 55 - .../ConsumerGroupMonitorMatchServiceImpl.java | 52 - .../impl/TopicMonitorMatchServiceImpl.java | 56 - .../manager/service/notify/KafkaNotifier.java | 37 - .../schedule/ScheduleCollectDataManager.java | 108 - .../schedule/ScheduleDeleteMetrics.java | 71 - .../schedule/ScheduleStoreMetrics.java | 118 - .../ScheduleTriggerTopicReassignmentTask.java | 72 - .../AdminPreferredReplicaElectService.java | 12 - .../service/service/AdminTopicService.java | 22 - .../service/service/AlarmRuleService.java | 22 - .../service/service/BrokerService.java | 47 - .../service/service/ClusterService.java | 28 - .../service/service/ConsumerService.java | 77 - .../manager/service/service/JmxService.java | 23 - .../manager/service/service/LoginService.java | 66 - .../service/service/MigrationService.java | 69 - .../manager/service/service/OrderService.java | 85 - .../service/service/RegionService.java | 48 - .../service/service/TopicManagerService.java | 39 - .../manager/service/service/TopicService.java | 72 - .../service/service/ZookeeperService.java | 21 - ...AdminPreferredReplicaElectServiceImpl.java | 127 - .../service/impl/AdminTopicServiceImpl.java | 193 - .../service/impl/AlarmRuleServiceImpl.java | 137 - .../service/impl/BrokerServiceImpl.java | 133 - .../service/impl/ClusterServiceImpl.java | 144 - .../service/service/impl/JmxServiceImpl.java | 212 - .../service/impl/LoginServiceImpl.java | 144 - .../service/impl/MigrationServiceImpl.java | 314 - .../service/impl/OrderServiceImpl.java | 127 - .../service/impl/RegionServiceImpl.java | 174 - .../service/impl/TopicManagerServiceImpl.java | 120 - .../service/impl/TopicServiceImpl.java | 450 - .../service/impl/ZookeeperServiceImpl.java | 63 - .../service/utils/BrokerMetadataUtil.java | 27 - .../manager/service/utils/ObjectUtil.java | 49 - web/bin/shutdown.sh | 16 - web/bin/startup.sh | 46 - web/conf/application.yml | 32 - .../versionone/AdminAccountController.java | 127 - .../versionone/AdminMigrationController.java | 111 - .../versionone/AdminRebalanceController.java | 81 - .../api/versionone/AdminRegionController.java | 95 - .../api/versionone/AdminUtilsController.java | 216 - .../web/api/versionone/AlarmController.java | 112 - .../web/api/versionone/BrokerController.java | 258 - .../web/api/versionone/ClusterController.java | 214 - .../api/versionone/ConsumerController.java | 168 - .../web/api/versionone/LoginController.java | 69 - .../web/api/versionone/OrderController.java | 357 - .../web/api/versionone/TopicController.java | 364 - .../web/converters/AccountConverter.java | 33 - .../converters/AdminMigrationConverter.java | 77 - .../web/converters/AdminUtilConverter.java | 73 - .../web/converters/AlarmConverter.java | 71 - .../web/converters/BrokerModelConverter.java | 294 - .../web/converters/ClusterModelConverter.java | 118 - .../web/converters/OrderConverter.java | 143 - .../web/converters/RegionModelConverter.java | 58 - .../web/converters/TopicModelConverter.java | 245 - .../web/inteceptor/PermissionInterceptor.java | 65 - .../web/inteceptor/WebMetricsInterceptor.java | 47 - .../kafka/manager/web/model/ClusterModel.java | 139 - .../web/model/MigrationCreateModel.java | 93 - .../manager/web/model/MigrationModel.java | 56 - .../manager/web/model/OffsetResetModel.java | 98 - .../web/model/alarm/AlarmRuleModel.java | 122 - .../model/order/OrderPartitionExecModel.java | 135 - .../web/model/order/OrderPartitionModel.java | 97 - .../web/model/order/OrderTopicExecModel.java | 161 - .../web/model/order/OrderTopicModel.java | 125 - .../web/model/topic/AdminTopicModel.java | 179 - .../web/model/topic/TopicDataSampleModel.java | 76 - .../web/model/topic/TopicDeleteModel.java | 48 - .../web/model/topic/TopicFavoriteModel.java | 46 - .../kafka/manager/web/vo/AccountVO.java | 50 - .../manager/web/vo/KafkaControllerVO.java | 73 - .../manager/web/vo/MigrationDetailVO.java | 118 - .../web/vo/PartitionReassignmentVO.java | 56 - .../manager/web/vo/alarm/AlarmConstantVO.java | 68 - .../manager/web/vo/alarm/AlarmRuleVO.java | 130 - .../web/vo/broker/BrokerKeyMetricsVO.java | 173 - .../web/vo/broker/BrokerOverallVO.java | 150 - .../web/vo/broker/BrokerOverviewVO.java | 151 - .../manager/web/vo/broker/BrokerStatusVO.java | 116 - .../web/vo/cluster/ClusterMetricsVO.java | 126 - .../manager/web/vo/topic/TopicMetadataVO.java | 103 - web/src/main/resources/application-pg.yml | 33 - web/src/main/resources/application.yml | 29 - web/src/main/resources/assembly.xml | 34 - 1253 files changed, 82183 insertions(+), 37179 deletions(-) delete mode 100644 Dockerfile delete mode 100644 common/pom.xml delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/Constant.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/MetricsType.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/OffsetStoreLocation.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/StatusCode.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorConditionType.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorMatchStatus.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorMetricsType.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorNotifyType.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetrics.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/annotations/FieldSelector.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/AccountRoleEnum.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/AdminTopicStatusEnum.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/DBStatusEnum.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/OperationEnum.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/OrderTypeEnum.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/PreferredReplicaElectEnum.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/ReassignmentStatusEnum.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerOverallDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerOverviewDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/ControllerDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicBasicDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicOverviewDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicPartitionDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmNotifyDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmRuleDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyActionDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyExpressionDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyFilterDTO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BaseMetrics.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BrokerMetrics.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicMetrics.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/AlarmRuleDO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BaseDO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BaseEntryDO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/ClusterMetricsDO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/MigrationTaskDO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OrderPartitionDO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OrderTopicDO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/RegionDO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/TopicDO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/TopicFavoriteDO.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/AlarmRuleQueryOption.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/BaseQueryOption.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/ClusterQueryOption.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DateUtils.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConnectorWrap.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtil.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/StateChangeListener.java delete mode 100644 common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/ZkPathUtil.java delete mode 100644 console/package-lock.json delete mode 100644 console/src/container/admin-consume/detail.tsx delete mode 100644 console/src/container/admin-consume/index.less delete mode 100644 console/src/container/admin-consume/index.tsx delete mode 100644 console/src/container/admin-controller/index.tsx delete mode 100644 console/src/container/admin-home/cluster-detail.tsx delete mode 100644 console/src/container/admin-home/index.less delete mode 100644 console/src/container/admin-home/index.tsx delete mode 100644 console/src/container/admin-operation/index.tsx delete mode 100644 console/src/container/admin-order/index.less delete mode 100644 console/src/container/admin-order/index.tsx delete mode 100644 console/src/container/admin-region/index.tsx delete mode 100644 console/src/container/admin-topic/index.tsx delete mode 100644 console/src/container/admin-usermanage/index.less delete mode 100644 console/src/container/admin-usermanage/index.tsx delete mode 100644 console/src/container/alarm/index.tsx delete mode 100644 console/src/container/broker-detail/base-detail.tsx delete mode 100644 console/src/container/broker-detail/broker-index.tsx delete mode 100644 console/src/container/broker-detail/broker-partition.tsx delete mode 100644 console/src/container/broker-detail/constant.ts delete mode 100644 console/src/container/broker-detail/index.tsx delete mode 100644 console/src/container/broker-detail/topic-analysis.tsx delete mode 100644 console/src/container/broker-detail/topic-info.tsx delete mode 100644 console/src/container/broker-info/base-info.tsx delete mode 100644 console/src/container/broker-info/broker-overview.tsx delete mode 100644 console/src/container/broker-info/constant.ts delete mode 100644 console/src/container/broker-info/index.less delete mode 100644 console/src/container/broker-info/index.tsx delete mode 100644 console/src/container/cluster-topic/index.tsx delete mode 100644 console/src/container/consumer/index.less delete mode 100644 console/src/container/consumer/index.tsx delete mode 100644 console/src/container/drawer/index.less delete mode 100644 console/src/container/drawer/index.tsx delete mode 100644 console/src/container/drawer/reset-offset.tsx delete mode 100644 console/src/container/drawer/topic-sample.tsx delete mode 100644 console/src/container/header/index.less delete mode 100644 console/src/container/header/index.tsx delete mode 100644 console/src/container/left-menu/constant.ts delete mode 100644 console/src/container/left-menu/index.tsx delete mode 100644 console/src/container/modal/admin-expand.tsx delete mode 100644 console/src/container/modal/alarm-config.tsx delete mode 100644 console/src/container/modal/cluster-network.tsx delete mode 100644 console/src/container/modal/cluster.tsx delete mode 100644 console/src/container/modal/cosumer-topic.tsx delete mode 100644 console/src/container/modal/index.tsx delete mode 100644 console/src/container/modal/leader-rebalance.tsx delete mode 100644 console/src/container/modal/new-user.tsx delete mode 100644 console/src/container/modal/order-approve.tsx delete mode 100644 console/src/container/modal/partition-approve.tsx delete mode 100644 console/src/container/modal/region.tsx delete mode 100644 console/src/container/modal/reset-offset.tsx delete mode 100644 console/src/container/modal/task-new.tsx delete mode 100644 console/src/container/modal/topic-create.tsx delete mode 100644 console/src/container/modal/topic-expand.tsx delete mode 100644 console/src/container/modal/topic-new.tsx delete mode 100644 console/src/container/modify-user/index.less delete mode 100644 console/src/container/modify-user/index.tsx delete mode 100644 console/src/container/my-order/index.tsx delete mode 100644 console/src/container/topic-detail/com.tsx delete mode 100644 console/src/container/topic-detail/index.less delete mode 100644 console/src/container/topic-detail/index.tsx delete mode 100644 console/src/container/user-home/index.less delete mode 100644 console/src/container/user-home/index.tsx delete mode 100644 console/src/lib/api.ts delete mode 100644 console/src/lib/charts-config.ts delete mode 100644 console/src/lib/fetch.ts delete mode 100644 console/src/lib/utils.ts delete mode 100644 console/src/routers/page/admin/index.tsx delete mode 100644 console/src/routers/page/home/index.tsx delete mode 100644 console/src/routers/router.tsx delete mode 100644 console/src/store/alarm.ts delete mode 100644 console/src/store/broker.ts delete mode 100644 console/src/store/cluster.ts delete mode 100644 console/src/store/controller.ts delete mode 100644 console/src/store/drawer.ts delete mode 100644 console/src/store/modal.ts delete mode 100644 console/src/store/operation.ts delete mode 100644 console/src/store/order.ts delete mode 100644 console/src/store/region.ts delete mode 100644 console/src/store/topic.ts delete mode 100644 console/src/store/users.ts delete mode 100644 console/src/types/base-type.ts delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/AlarmRuleDao.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/MigrationTaskDao.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OperationHistoryDao.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OrderPartitionDao.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OrderTopicDao.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicFavoriteDao.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/AlarmRuleDaoImpl.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/KafkaManagerProperties.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/MigrationTaskDaoImpl.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OperationHistoryDaoImpl.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OrderPartitionDaoImpl.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OrderTopicDaoImpl.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicDaoImpl.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicFavoriteDaoImpl.java delete mode 100644 dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicMetricsDaoImpl.java delete mode 100644 dao/src/main/resources/mapper/AccountDao.xml delete mode 100644 dao/src/main/resources/mapper/AlarmRuleDao.xml delete mode 100644 dao/src/main/resources/mapper/BrokerDao.xml delete mode 100644 dao/src/main/resources/mapper/BrokerMetricsDao.xml delete mode 100644 dao/src/main/resources/mapper/ClusterDao.xml delete mode 100644 dao/src/main/resources/mapper/ClusterMetricsDao.xml delete mode 100644 dao/src/main/resources/mapper/MigrationTaskDao.xml delete mode 100644 dao/src/main/resources/mapper/OperationHistoryDao.xml delete mode 100644 dao/src/main/resources/mapper/OrderPartitionDao.xml delete mode 100644 dao/src/main/resources/mapper/OrderTopicDao.xml delete mode 100644 dao/src/main/resources/mapper/RegionDao.xml delete mode 100644 dao/src/main/resources/mapper/TopicDao.xml delete mode 100644 dao/src/main/resources/mapper/TopicFavoriteDao.xml delete mode 100644 dao/src/main/resources/mapper/TopicMetricsDao.xml delete mode 100644 dao/src/main/resources/spring-dao.xml delete mode 100644 doc/assets/images/kafka_manager_cn_guide/admin_add_cluster.jpg delete mode 100644 doc/assets/images/kafka_manager_cn_guide/admin_cluster_broker_detail.jpg delete mode 100644 doc/assets/images/kafka_manager_cn_guide/admin_cluster_details.jpg delete mode 100644 doc/assets/images/kafka_manager_cn_guide/admin_manager_account.jpg delete mode 100644 doc/assets/images/kafka_manager_cn_guide/admin_order.jpg delete mode 100644 doc/assets/images/kafka_manager_cn_guide/my_order_list.jpg delete mode 100644 doc/assets/images/kafka_manager_cn_guide/normal_create_alarm_rule.jpg delete mode 100644 doc/assets/images/kafka_manager_cn_guide/normal_modify_password.jpg delete mode 100644 doc/assets/images/kafka_manager_cn_guide/normal_reset_consume_offset.jpg delete mode 100644 doc/assets/images/kafka_manager_cn_guide/normal_topic_detail.jpg delete mode 100644 doc/create_mysql_table.sql delete mode 100644 doc/create_postgresql_table.sql delete mode 100644 docker-compose.yml delete mode 100644 docker/kafka-manager/Dockerfile delete mode 100644 docker/kafka-manager/application-standalone.yml delete mode 100644 docker/kafka-manager/application.yml delete mode 100644 docker/mysql/Dockerfile delete mode 100644 docker/mysql/create_mysql_table.sql rename {doc => docs}/assets/images/common/arch.png (100%) rename {doc => docs}/assets/images/common/dingding_group.jpg (100%) rename {doc => docs}/assets/images/common/logo_name.png (100%) create mode 100644 docs/create_mysql_table.sql create mode 100644 docs/install_cn_guide.md create mode 100644 docs/manual_kafka_op/add_cluster.md create mode 100644 docs/manual_kafka_op/imgs/op_add_cluster.jpg create mode 100644 docs/manual_kafka_op/imgs/op_add_logical_cluster.jpg create mode 100644 docs/manual_kafka_op/imgs/op_add_region.jpg rename {doc => docs}/user_cn_guide.md (100%) create mode 100644 kafka-manager-common/pom.xml create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/annotations/ApiLevel.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/AccountRoleEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ApiLevelEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ClusterComboEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ClusterModeEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/DBStatusEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/IDCEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaBrokerRoleEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaClientEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaFileEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ModuleEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OffsetLocationEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OffsetPosEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OperateEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OperationStatusEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/PeakFlowStatusEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/RebalanceDimensionEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/SinkMonitorSystemEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TaskStatusEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TaskStatusReassignEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicAuthorityEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicOffsetChangedEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicReassignActionEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/gateway/GatewayConfigKeyEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ApiLevelContent.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ApiPrefix.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ConfigConstant.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/Constant.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/KafkaConstant.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/KafkaMetricsCollections.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/LogConstant.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/LoginConstant.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/SystemCodeConstant.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/TopicCreationConstant.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/TopicSampleConstant.java rename {common => kafka-manager-common}/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetadata.java (73%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/DeprecatedResponseResult.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/KafkaVersion.java rename {common => kafka-manager-common}/src/main/java/com/xiaojukeji/kafka/manager/common/entity/Result.java (52%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ResultStatus.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/TopicOperationResult.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/AppTopicDTO.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao}/BrokerBasicDTO.java (97%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/BrokerOverviewDTO.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/cluster/ClusterDetailVO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/ClusterDetailDTO.java (56%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/PartitionAttributeDTO.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao}/PartitionOffsetDTO.java (95%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/RdTopicBasic.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/TopicDiskLocation.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/account/Account.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao}/analysis/AnalysisBrokerDTO.java (97%) rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao}/analysis/AnalysisTopicDTO.java (98%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/api/ApiCount.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/ClusterBrokerStatus.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/LogicalCluster.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicMetricsVO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/LogicalClusterMetrics.java (70%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/CreateTopicConfig.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/AdminExpandTopicModel.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/CreateTopicElemConfig.java (50%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/MaxAvgBytesInConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/SinkTopicRequestTimeMetricsConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/TopicAnomalyFlowConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/TopicNameConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/RegionTopicHotConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/TopicExpiredConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/TopicInsufficientPartitionConfig.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao}/consumer/ConsumeDetailDTO.java (94%) rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao}/consumer/ConsumerGroupDTO.java (65%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicAnomalyFlow.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicInsufficientPartition.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicRegionHot.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/AppRateConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/BaseGatewayConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/IpRateConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/KafkaBootstrapServerConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/RequestQueueConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/SpRateConfig.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/TopicQuota.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/reassign/ReassignStatus.java rename common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/consumer/ConsumerDTO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaConsumerMetrics.java (51%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaConsumerMetricsElem.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaTopicMetrics.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/MineTopicSummary.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicAppData.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicBasicVO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBasicDTO.java (60%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBrokerDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBusinessInfo.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicConnection.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicExpiredData.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicMetricsDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicOverview.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicPartitionVO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicPartitionDTO.java (60%) rename web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/TopicFavorite.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/ClusterTopicDTO.java (58%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/config/ConfigDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/KafkaAclSearchDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/KafkaUserSearchDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/TopicConnectionDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/AppDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/JmxSwitchDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/KafkaFileDTO.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/model/LoginModel.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/LoginDTO.java (66%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicDataSampleDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicModifyDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicOffsetResetDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicRetainDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/KafkaPackageDTO.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/model/RebalanceModel.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/RebalanceDTO.java (51%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignExecDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignExecSubDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignTopicDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicCreationDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicDeletionDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicExpansionDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicModificationDTO.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/model/AccountModel.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/AccountDTO.java (51%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/ClusterDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/CustomScheduledTaskDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/LogicalClusterDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/OperateRecordDTO.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/model/RegionModel.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/RegionDTO.java (53%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BaseMetrics.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BrokerMetrics.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/ClusterMetrics.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/ConsumerMetrics.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicMetrics.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicThrottledMetrics.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo}/AccountDO.java (81%) rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo}/BrokerDO.java (53%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/BrokerMetricsDO.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo}/ClusterDO.java (59%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterMetricsDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterTaskDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterTaskDetailDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ConfigDO.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo}/ControllerDO.java (81%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/HeartbeatDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/KafkaBillDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/KafkaFileDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/LogicalClusterDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/MonitorRuleDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OperateRecordDO.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo}/OperationHistoryDO.java (73%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OrderDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ReassignTaskDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/RegionDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicExpiredDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicMetricsDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicStatisticsDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicThrottledMetricsDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/AppDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/AuthorityDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/GatewayConfigDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/KafkaAclDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/KafkaUserDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/TopicConnectionDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/TopicReportDO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountRoleVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountSummaryVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/BrokerOverviewVO.java rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/order => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common}/OrderPartitionVO.java (98%) rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/order => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common}/OrderTopicVO.java (98%) rename web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicRealTimeMetricsVO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/RealTimeMetricsVO.java (78%) rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common}/TopicOverviewVO.java (54%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/TopicThrottleVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/GatewayConfigVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaAclVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaSecurityVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaUserVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillStaffDetailVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillStaffSummaryVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillTopicVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/QuotaVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/TopicBusinessInfoVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppSummaryVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppTopicAuthorityVO.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/MigrationTaskVO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppTopicVO.java (56%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/DeprecatedAppVO.java rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal}/cluster/ClusterBasicVO.java (97%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/ClusterNameDTO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/LogicClusterVO.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerMetricsVO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/NormalClusterMetricsVO.java (61%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/TopicMetadataVO.java rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal}/consumer/ConsumerGroupDetailVO.java (77%) rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal}/consumer/ConsumerGroupVO.java (56%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderResultVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderTypeVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/detail/OrderDetailBaseVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicAuthorizedAppVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicBasicVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicBillVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicConnectionVO.java rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal}/topic/TopicDataSampleVO.java (89%) rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal}/topic/TopicDeleteVO.java (96%) rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal}/topic/TopicDetailVO.java (97%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicExpiredVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMetricVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMineVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMyAppVO.java rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal}/topic/TopicOffsetVO.java (96%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicPartitionVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicRequestTimeDetailVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicRequestTimeVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/AnomalyFlowTopicVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/BrokerIdPartitionNumVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/ExpiredTopicVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/PartitionInsufficientTopicVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/RegionHotTopicVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignPartitionStatusVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignTaskVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignTopicStatusVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskKafkaFilesVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskMetadataVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskStatusVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskSubStatusVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/ConfigVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/CustomScheduledTaskVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/KafkaControllerVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/KafkaFileVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/OperateRecordVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/RdTopicBasicVO.java rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd}/RegionVO.java (53%) rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd}/TopicBrokerVO.java (74%) rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd}/broker/AnalysisBrokerVO.java (97%) rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd}/broker/AnalysisTopicVO.java (98%) rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd}/broker/BrokerBasicVO.java (89%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerDiskTopicVO.java rename {web/src/main/java/com/xiaojukeji/kafka/manager/web/vo => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd}/broker/BrokerMetadataVO.java (92%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerMetricsVO.java rename web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerPartitionsVO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerPartitionVO.java (89%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/RdBrokerBasicVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterBaseVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterBrokerStatusVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterDetailVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/LogicalClusterVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/RdClusterMetricsVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/thirdpart/AppBasicInfoVO.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/ConsumerMetricsCollectedEvent.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderApplyEvent.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderEvent.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderPassedEvent.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderRefusedEvent.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/TopicMetricsCollectedEvent.java rename {common => kafka-manager-common}/src/main/java/com/xiaojukeji/kafka/manager/common/exception/ConfigException.java (100%) rename {common => kafka-manager-common}/src/main/java/com/xiaojukeji/kafka/manager/common/exception/CopyException.java (100%) rename {common => kafka-manager-common}/src/main/java/com/xiaojukeji/kafka/manager/common/utils/CopyUtils.java (99%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DateUtils.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EasyApiLimitUtils.java rename {common => kafka-manager-common}/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EncryptUtil.java (91%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/HttpUtils.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/JsonUtils.java rename {service/src/main/java/com/xiaojukeji/kafka/manager/service => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common}/utils/ListUtils.java (82%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/NetUtils.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/NumberUtils.java rename service/src/main/java/com/xiaojukeji/kafka/manager/service/utils/SpringContextHolder.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/SpringTool.java (52%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/UUIDUtils.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/ValidateUtils.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/utils => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/factory}/DefaultThreadFactory.java (94%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/factory/KafkaConsumerFactory.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxAttributeEnum.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConnectorWrap.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConstant.java rename {common => kafka-manager-common}/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/Mbean.java (100%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtil.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtilV2.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanV2.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper}/ConfigClient.java (98%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/StateChangeListener.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper}/ZkConfigImpl.java (99%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/ZkPathUtil.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode}/ControllerData.java (93%) rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode}/ReassignmentDTO.java (94%) rename common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentElemDTO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentElemData.java (90%) rename common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentJsonDTO.java => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentJsonData.java (65%) rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers}/BrokerMetadata.java (94%) rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers}/PartitionMap.java (80%) rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers}/PartitionState.java (96%) rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper => kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers}/TopicMetadata.java (96%) create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/ChangeData.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/ConfigNodeData.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/TopicQuotaData.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/didi/JmxSwitchDataConstant.java create mode 100644 kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/didi/TopicJmxSwitch.java rename {console => kafka-manager-console}/package.json (80%) rename {console => kafka-manager-console}/pom.xml (97%) rename {console => kafka-manager-console}/src/assets/image/admin.png (100%) rename {console => kafka-manager-console}/src/assets/image/devops.png (100%) rename {console => kafka-manager-console}/src/assets/image/images.d.ts (100%) rename {console => kafka-manager-console}/src/assets/image/kafka-logo.png (100%) rename {console => kafka-manager-console}/src/assets/image/kafka-manager.png (100%) rename {console => kafka-manager-console}/src/assets/image/login-bg.png (100%) rename {console => kafka-manager-console}/src/assets/image/logo.ico (100%) rename {console => kafka-manager-console}/src/assets/image/normal.png (100%) create mode 100644 kafka-manager-console/src/assets/image/wechat.jpeg rename {console => kafka-manager-console}/src/component/antd/index.tsx (72%) create mode 100644 kafka-manager-console/src/component/chart/bar-chart.tsx create mode 100644 kafka-manager-console/src/component/chart/date-picker-chart.tsx create mode 100644 kafka-manager-console/src/component/chart/doughnut-chart.tsx create mode 100644 kafka-manager-console/src/component/chart/index.less create mode 100644 kafka-manager-console/src/component/chart/index.tsx create mode 100644 kafka-manager-console/src/component/chart/line-chart.tsx create mode 100755 kafka-manager-console/src/component/clipboard/index.tsx create mode 100644 kafka-manager-console/src/component/expand-card/index.less create mode 100644 kafka-manager-console/src/component/expand-card/index.tsx rename {console => kafka-manager-console}/src/component/flow-table/index.tsx (64%) create mode 100644 kafka-manager-console/src/component/virtual-scroll-select.tsx create mode 100755 kafka-manager-console/src/component/x-form-wrapper/index.tsx create mode 100644 kafka-manager-console/src/component/x-form/index.less create mode 100755 kafka-manager-console/src/component/x-form/index.tsx create mode 100644 kafka-manager-console/src/constants/left-menu.ts create mode 100644 kafka-manager-console/src/constants/status-map.ts create mode 100644 kafka-manager-console/src/constants/strategy.ts create mode 100644 kafka-manager-console/src/constants/table.ts create mode 100644 kafka-manager-console/src/container/admin/admin-app-list.tsx create mode 100644 kafka-manager-console/src/container/admin/bill-detail.tsx create mode 100644 kafka-manager-console/src/container/admin/bill-management/index.less create mode 100644 kafka-manager-console/src/container/admin/bill-management/index.tsx create mode 100644 kafka-manager-console/src/container/admin/bill-management/personal-bill.tsx create mode 100644 kafka-manager-console/src/container/admin/broker-detail/base-info.tsx create mode 100644 kafka-manager-console/src/container/admin/broker-detail/disk-info.tsx rename {console/src/container => kafka-manager-console/src/container/admin}/broker-detail/index.less (61%) create mode 100644 kafka-manager-console/src/container/admin/broker-detail/index.tsx create mode 100644 kafka-manager-console/src/container/admin/broker-detail/monitor-info.tsx create mode 100644 kafka-manager-console/src/container/admin/broker-detail/partition-info.tsx create mode 100644 kafka-manager-console/src/container/admin/broker-detail/topic-analysis.tsx create mode 100644 kafka-manager-console/src/container/admin/broker-detail/topic-info.tsx create mode 100644 kafka-manager-console/src/container/admin/cluster-detail/cluster-broker.tsx create mode 100644 kafka-manager-console/src/container/admin/cluster-detail/cluster-consumer.tsx create mode 100644 kafka-manager-console/src/container/admin/cluster-detail/cluster-controller.tsx create mode 100644 kafka-manager-console/src/container/admin/cluster-detail/cluster-overview.tsx create mode 100644 kafka-manager-console/src/container/admin/cluster-detail/cluster-topic.tsx create mode 100644 kafka-manager-console/src/container/admin/cluster-detail/current-limiting.tsx create mode 100644 kafka-manager-console/src/container/admin/cluster-detail/exclusive-cluster.tsx create mode 100644 kafka-manager-console/src/container/admin/cluster-detail/index.less create mode 100644 kafka-manager-console/src/container/admin/cluster-detail/index.tsx create mode 100644 kafka-manager-console/src/container/admin/cluster-detail/logical-cluster.tsx create mode 100644 kafka-manager-console/src/container/admin/cluster-list/index.less create mode 100644 kafka-manager-console/src/container/admin/cluster-list/index.tsx create mode 100644 kafka-manager-console/src/container/admin/config.tsx create mode 100644 kafka-manager-console/src/container/admin/configure-management.tsx create mode 100644 kafka-manager-console/src/container/admin/data-curve/config.ts create mode 100644 kafka-manager-console/src/container/admin/data-curve/index.less create mode 100644 kafka-manager-console/src/container/admin/data-curve/index.tsx create mode 100644 kafka-manager-console/src/container/admin/data-curve/parser.ts create mode 100644 kafka-manager-console/src/container/admin/index.tsx create mode 100644 kafka-manager-console/src/container/admin/individual-bill.tsx create mode 100644 kafka-manager-console/src/container/admin/operation-detail/essential-info.tsx create mode 100644 kafka-manager-console/src/container/admin/operation-detail/index.less create mode 100644 kafka-manager-console/src/container/admin/operation-detail/index.tsx create mode 100644 kafka-manager-console/src/container/admin/operation-detail/taskStatus-details.tsx create mode 100644 kafka-manager-console/src/container/admin/operation-management/cluster-task.tsx create mode 100644 kafka-manager-console/src/container/admin/operation-management/config.tsx create mode 100644 kafka-manager-console/src/container/admin/operation-management/index.less create mode 100644 kafka-manager-console/src/container/admin/operation-management/index.tsx create mode 100644 kafka-manager-console/src/container/admin/operation-management/migration-detail.tsx create mode 100644 kafka-manager-console/src/container/admin/operation-management/migration-task.tsx create mode 100644 kafka-manager-console/src/container/admin/platform-management.tsx create mode 100644 kafka-manager-console/src/container/admin/user-management.tsx create mode 100644 kafka-manager-console/src/container/admin/version-management.tsx create mode 100644 kafka-manager-console/src/container/alarm/add-alarm/action-form.tsx create mode 100644 kafka-manager-console/src/container/alarm/add-alarm/alarm-select.tsx create mode 100644 kafka-manager-console/src/container/alarm/add-alarm/config.tsx create mode 100644 kafka-manager-console/src/container/alarm/add-alarm/filter-form.tsx create mode 100644 kafka-manager-console/src/container/alarm/add-alarm/index.less create mode 100644 kafka-manager-console/src/container/alarm/add-alarm/index.tsx create mode 100644 kafka-manager-console/src/container/alarm/add-alarm/strategy-form.tsx create mode 100644 kafka-manager-console/src/container/alarm/add-alarm/time-form.tsx create mode 100644 kafka-manager-console/src/container/alarm/add-alarm/type-form.tsx create mode 100644 kafka-manager-console/src/container/alarm/alarm-detail/alarm-history.tsx create mode 100644 kafka-manager-console/src/container/alarm/alarm-detail/history-detail.tsx create mode 100644 kafka-manager-console/src/container/alarm/alarm-detail/index.less create mode 100644 kafka-manager-console/src/container/alarm/alarm-detail/index.tsx create mode 100644 kafka-manager-console/src/container/alarm/alarm-detail/shield-history.tsx create mode 100644 kafka-manager-console/src/container/alarm/alarm-list.tsx create mode 100644 kafka-manager-console/src/container/alarm/index.tsx create mode 100644 kafka-manager-console/src/container/app-select.tsx create mode 100644 kafka-manager-console/src/container/app/app-detail.tsx create mode 100644 kafka-manager-console/src/container/app/app-list.tsx create mode 100644 kafka-manager-console/src/container/app/index.less create mode 100644 kafka-manager-console/src/container/app/index.tsx create mode 100644 kafka-manager-console/src/container/cluster/cluster-detail/cluster-broker.tsx create mode 100644 kafka-manager-console/src/container/cluster/cluster-detail/cluster-overview.tsx create mode 100644 kafka-manager-console/src/container/cluster/cluster-detail/cluster-topic.tsx create mode 100644 kafka-manager-console/src/container/cluster/cluster-detail/current-limiting.tsx create mode 100644 kafka-manager-console/src/container/cluster/cluster-detail/index.less create mode 100644 kafka-manager-console/src/container/cluster/cluster-detail/index.tsx create mode 100644 kafka-manager-console/src/container/cluster/config.tsx create mode 100644 kafka-manager-console/src/container/cluster/index.less create mode 100644 kafka-manager-console/src/container/cluster/index.tsx create mode 100644 kafka-manager-console/src/container/cluster/my-cluster.tsx create mode 100644 kafka-manager-console/src/container/common-curve/config.ts create mode 100644 kafka-manager-console/src/container/common-curve/index.less create mode 100644 kafka-manager-console/src/container/common-curve/index.tsx create mode 100644 kafka-manager-console/src/container/configure-info.tsx create mode 100644 kafka-manager-console/src/container/custom-component.tsx create mode 100644 kafka-manager-console/src/container/drawer/add-alarm.tsx create mode 100644 kafka-manager-console/src/container/drawer/data-migration.tsx create mode 100644 kafka-manager-console/src/container/error/forbidden.tsx create mode 100644 kafka-manager-console/src/container/error/index.less create mode 100644 kafka-manager-console/src/container/error/index.tsx create mode 100644 kafka-manager-console/src/container/expert/diagnosis/index.less create mode 100644 kafka-manager-console/src/container/expert/diagnosis/index.tsx create mode 100644 kafka-manager-console/src/container/expert/index.tsx create mode 100644 kafka-manager-console/src/container/expert/topic-governance/index.less create mode 100644 kafka-manager-console/src/container/expert/topic-governance/index.tsx create mode 100644 kafka-manager-console/src/container/expert/topic-hotspot/index.less create mode 100644 kafka-manager-console/src/container/expert/topic-hotspot/index.tsx create mode 100644 kafka-manager-console/src/container/expert/topic-partition/batch-expansion.tsx create mode 100644 kafka-manager-console/src/container/expert/topic-partition/index.less create mode 100644 kafka-manager-console/src/container/expert/topic-partition/index.tsx create mode 100644 kafka-manager-console/src/container/full-screen/index.less create mode 100644 kafka-manager-console/src/container/full-screen/index.tsx create mode 100644 kafka-manager-console/src/container/header/index.less create mode 100644 kafka-manager-console/src/container/header/index.tsx rename {console => kafka-manager-console}/src/container/left-menu/index.less (87%) create mode 100644 kafka-manager-console/src/container/left-menu/index.tsx create mode 100644 kafka-manager-console/src/container/modal/admin/cluster.ts create mode 100644 kafka-manager-console/src/container/modal/admin/expand-partition.tsx create mode 100644 kafka-manager-console/src/container/modal/admin/index.ts create mode 100644 kafka-manager-console/src/container/modal/admin/leader-rebalance.tsx create mode 100644 kafka-manager-console/src/container/modal/admin/migration.ts create mode 100644 kafka-manager-console/src/container/modal/admin/task.ts create mode 100644 kafka-manager-console/src/container/modal/admin/user.ts create mode 100644 kafka-manager-console/src/container/modal/admin/version.ts create mode 100644 kafka-manager-console/src/container/modal/alarm.tsx create mode 100644 kafka-manager-console/src/container/modal/app.tsx create mode 100644 kafka-manager-console/src/container/modal/cancel-topic-permission.tsx create mode 100644 kafka-manager-console/src/container/modal/cluster.tsx create mode 100644 kafka-manager-console/src/container/modal/connect-topic-list.tsx create mode 100644 kafka-manager-console/src/container/modal/expert.tsx create mode 100644 kafka-manager-console/src/container/modal/index.tsx create mode 100644 kafka-manager-console/src/container/modal/offline-app-modal.tsx create mode 100644 kafka-manager-console/src/container/modal/offline-cluster-modal.tsx create mode 100644 kafka-manager-console/src/container/modal/order.tsx create mode 100644 kafka-manager-console/src/container/modal/render-order-op-result.tsx create mode 100644 kafka-manager-console/src/container/modal/topic.tsx create mode 100644 kafka-manager-console/src/container/network-flow.tsx create mode 100644 kafka-manager-console/src/container/search-filter.tsx create mode 100644 kafka-manager-console/src/container/staff-select.tsx create mode 100644 kafka-manager-console/src/container/topic/config.tsx create mode 100644 kafka-manager-console/src/container/topic/index.less create mode 100644 kafka-manager-console/src/container/topic/index.tsx create mode 100644 kafka-manager-console/src/container/topic/peak-flow.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-all.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-app-list.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-app-select.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/appid-information.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/base-information.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/bill-information.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/brokers-information.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/common-detail.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/connect-information.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/group-id.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/index.less create mode 100644 kafka-manager-console/src/container/topic/topic-detail/index.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/partition-information.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/reset-offset.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-detail/status-chart.tsx create mode 100644 kafka-manager-console/src/container/topic/topic-mine.tsx create mode 100644 kafka-manager-console/src/container/user-center/bill-detaill.tsx create mode 100644 kafka-manager-console/src/container/user-center/config.tsx create mode 100644 kafka-manager-console/src/container/user-center/index.less create mode 100644 kafka-manager-console/src/container/user-center/index.tsx create mode 100644 kafka-manager-console/src/container/user-center/my-approval.tsx create mode 100644 kafka-manager-console/src/container/user-center/my-bill.tsx create mode 100644 kafka-manager-console/src/container/user-center/my-order.tsx create mode 100644 kafka-manager-console/src/container/user-center/order-detail.tsx create mode 100644 kafka-manager-console/src/container/user-center/order-list.tsx create mode 100644 kafka-manager-console/src/container/wrapper/custom-modal.tsx rename {console/src/container/modal => kafka-manager-console/src/container/wrapper}/index.less (77%) create mode 100644 kafka-manager-console/src/container/wrapper/index.tsx create mode 100644 kafka-manager-console/src/lib/api-cache.ts create mode 100644 kafka-manager-console/src/lib/api.ts create mode 100644 kafka-manager-console/src/lib/bar-pie-config.ts create mode 100644 kafka-manager-console/src/lib/chart-utils.ts create mode 100644 kafka-manager-console/src/lib/fetch.ts create mode 100644 kafka-manager-console/src/lib/line-charts-config.ts create mode 100644 kafka-manager-console/src/lib/local-storage.ts rename {console => kafka-manager-console}/src/lib/url-parser.ts (99%) create mode 100644 kafka-manager-console/src/lib/utils.ts rename {console => kafka-manager-console}/src/routers/index.htm (53%) rename {console => kafka-manager-console}/src/routers/index.tsx (89%) create mode 100644 kafka-manager-console/src/routers/page/admin.tsx create mode 100644 kafka-manager-console/src/routers/page/alarm.tsx create mode 100644 kafka-manager-console/src/routers/page/cluster.tsx create mode 100644 kafka-manager-console/src/routers/page/common.tsx create mode 100644 kafka-manager-console/src/routers/page/error.tsx create mode 100644 kafka-manager-console/src/routers/page/expert.tsx rename {console/src/routers/page/home => kafka-manager-console/src/routers/page}/index.less (86%) create mode 100644 kafka-manager-console/src/routers/page/info.tsx rename {console => kafka-manager-console}/src/routers/page/login/index.less (100%) rename {console => kafka-manager-console}/src/routers/page/login/index.tsx (95%) create mode 100644 kafka-manager-console/src/routers/page/login/sso-callback.tsx create mode 100644 kafka-manager-console/src/routers/page/topic.tsx create mode 100644 kafka-manager-console/src/routers/page/user.tsx create mode 100644 kafka-manager-console/src/routers/router.tsx create mode 100644 kafka-manager-console/src/store/admin-monitor.ts create mode 100644 kafka-manager-console/src/store/admin.ts create mode 100644 kafka-manager-console/src/store/alarm.ts create mode 100644 kafka-manager-console/src/store/app.ts create mode 100644 kafka-manager-console/src/store/bill.ts create mode 100644 kafka-manager-console/src/store/cluster.ts rename {console => kafka-manager-console}/src/store/consume.ts (94%) create mode 100644 kafka-manager-console/src/store/curve-info.ts create mode 100644 kafka-manager-console/src/store/expert.ts create mode 100644 kafka-manager-console/src/store/full-screen.ts rename {console => kafka-manager-console}/src/store/index.ts (52%) create mode 100644 kafka-manager-console/src/store/modal.ts create mode 100644 kafka-manager-console/src/store/order.ts create mode 100644 kafka-manager-console/src/store/region.ts create mode 100644 kafka-manager-console/src/store/time.ts create mode 100644 kafka-manager-console/src/store/topic.ts rename {console => kafka-manager-console}/src/store/url-query.ts (87%) create mode 100644 kafka-manager-console/src/store/users.ts create mode 100644 kafka-manager-console/src/store/version.ts create mode 100644 kafka-manager-console/src/store/wrapper.ts create mode 100644 kafka-manager-console/src/styles/custom-component.less create mode 100644 kafka-manager-console/src/styles/header-search.less create mode 100644 kafka-manager-console/src/styles/search-filter.less create mode 100644 kafka-manager-console/src/styles/table-filter.less create mode 100644 kafka-manager-console/src/styles/theme-dark.less create mode 100644 kafka-manager-console/src/types/alarm.ts create mode 100644 kafka-manager-console/src/types/base-type.ts rename {console => kafka-manager-console}/tsconfig.json (100%) rename {console => kafka-manager-console}/tslint.json (95%) rename {console => kafka-manager-console}/webpack.config.js (92%) rename {service => kafka-manager-core}/pom.xml (71%) rename {service => kafka-manager-core}/src/main/java/com/xiaojukeji/kafka/manager/service/cache/ConsumerMetadataCache.java (60%) create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/cache/KafkaClientPool.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/cache/KafkaMetricsCache.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/cache/LogicalClusterMetadataManager.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/cache/PhysicalClusterMetadataManager.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/cache/ThreadPool.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/AdminService.java rename {service => kafka-manager-core}/src/main/java/com/xiaojukeji/kafka/manager/service/service/AnalysisService.java (75%) create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/BrokerService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/ClusterService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/ConfigService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/ConsumerService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/ExpertService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/JmxService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/KafkaBillService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/LogicalClusterService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/OperateRecordService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/ReassignService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/RegionService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/ThrottleService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/TopicExpiredService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/TopicManagerService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/TopicService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/ZookeeperService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/AppService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/AuthorityService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/GatewayConfigService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/QuotaService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/SecurityService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/TopicConnectionService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/TopicReportService.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/impl/AppServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/impl/AuthorityServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/impl/GatewayConfigServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/impl/QuotaServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/impl/SecurityServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/impl/TopicConnectionServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/gateway/impl/TopicReportServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/AdminServiceImpl.java rename {service => kafka-manager-core}/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/AnalysisServiceImpl.java (61%) create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/BrokerServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/ClusterServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/ConfigServiceImpl.java rename {service => kafka-manager-core}/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/ConsumerServiceImpl.java (56%) create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/ExpertServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/JmxServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/KafkaBillServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/LogicalClusterServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/OperateRecordServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/ReassignServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/RegionServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/ThrottleServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/TopicExpiredServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/TopicManagerServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/TopicServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/ZookeeperServiceImpl.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/strategy/AbstractAllocateQuotaStrategy.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/strategy/AbstractHealthScoreStrategy.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/strategy/healthscore/DidiHealthScoreStrategy.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/strategy/quota/BaseAllocateQuotaStrategy.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/utils/ConfigUtils.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/utils/KafkaZookeeperUtils.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/utils/MetricsConvertUtils.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/utils/TopicCommands.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/utils/TopicReassignUtils.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/zookeeper/BrokerStateListener.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/zookeeper/ControllerStateListener.java create mode 100644 kafka-manager-core/src/main/java/com/xiaojukeji/kafka/manager/service/zookeeper/TopicStateListener.java rename {service => kafka-manager-core}/src/test/java/META-INF/MANIFEST.MF (100%) rename {service => kafka-manager-core}/src/test/java/com/xiaojukeji/kafka/manager/service/FutureTest.java (100%) rename {service => kafka-manager-core}/src/test/java/com/xiaojukeji/kafka/manager/service/utils/SpringTestBase.java (100%) rename {dao => kafka-manager-dao}/pom.xml (75%) rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/AccountDao.java (64%) rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/BrokerDao.java (66%) rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/BrokerMetricsDao.java (56%) rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/ClusterDao.java (75%) rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/ClusterMetricsDao.java (57%) create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/ClusterTaskDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/ConfigDao.java rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/ControllerDao.java (75%) create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/HeartbeatDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/KafkaBillDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/KafkaFileDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/LogicalClusterDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/MonitorRuleDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OperateRecordDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OrderDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/ReassignTaskDao.java rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/RegionDao.java (75%) create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicAppMetricsDao.java rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicDao.java (52%) create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicExpiredDao.java rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicMetricsDao.java (52%) create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicRequestMetricsDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicStatisticsDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicThrottledMetricsDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/AppDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/AuthorityDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/GatewayConfigDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/KafkaAclDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/KafkaUserDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/TopicConnectionDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/TopicReportDao.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/impl/AppDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/impl/AuthorityDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/impl/GatewayConfigDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/impl/KafkaAclDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/impl/KafkaUserDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/impl/TopicConnectionDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/gateway/impl/TopicReportDaoImpl.java rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/AccountDaoImpl.java (69%) rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/BrokerDaoImpl.java (70%) rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/BrokerMetricsImpl.java (62%) rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/ClusterDaoImpl.java (71%) rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/ClusterMetricsDaoImpl.java (80%) create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/ClusterTaskDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/ConfigDaoImpl.java rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/ControllerDaoImpl.java (92%) create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/HeartbeatDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/KafkaBillDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/KafkaFileDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/LogicalClusterDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/MonitorRuleDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OperateRecordDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OrderDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/ReassignTaskDaoImpl.java rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/RegionDaoImpl.java (83%) create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicAppMetricsDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicExpiredDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicMetricsDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicRequestMetricsDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicStatisticsDaoImpl.java create mode 100644 kafka-manager-dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicThrottledMetricsDaoImpl.java rename {dao => kafka-manager-dao}/src/main/java/com/xiaojukeji/kafka/manager/vfs/SpringBootVFS.java (100%) create mode 100644 kafka-manager-dao/src/main/resources/mapper/AccountDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/AppDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/AuthorityDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/BrokerDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/BrokerMetricsDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/ClusterDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/ClusterMetricsDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/ClusterTaskDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/ConfigDao.xml rename {dao => kafka-manager-dao}/src/main/resources/mapper/ControllerDao.xml (53%) create mode 100644 kafka-manager-dao/src/main/resources/mapper/GatewayConfigDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/HeartbeatDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/KafkaAclDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/KafkaBillDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/KafkaFileDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/KafkaUserDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/LogicalClusterDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/MonitorRuleDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/OperateRecordDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/OrderDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/ReassignTaskDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/RegionDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/TopicAppMetricsDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/TopicConnectionDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/TopicDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/TopicExpiredDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/TopicMetricsDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/TopicReportDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/TopicRequestMetricsDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/TopicStatisticsDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/TopicThrottledMetricsDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/gateway/DeprecatedKafkaAclDao.xml create mode 100644 kafka-manager-dao/src/main/resources/mapper/gateway/DeprecatedKafkaUserDao.xml rename {dao => kafka-manager-dao}/src/main/resources/mybatis-config.xml (98%) create mode 100644 kafka-manager-extends/kafka-manager-account/pom.xml create mode 100644 kafka-manager-extends/kafka-manager-account/src/main/java/com/xiaojukeji/kafka/manager/account/AccountService.java create mode 100644 kafka-manager-extends/kafka-manager-account/src/main/java/com/xiaojukeji/kafka/manager/account/LoginService.java create mode 100644 kafka-manager-extends/kafka-manager-account/src/main/java/com/xiaojukeji/kafka/manager/account/common/EnterpriseStaff.java create mode 100644 kafka-manager-extends/kafka-manager-account/src/main/java/com/xiaojukeji/kafka/manager/account/component/AbstractEnterpriseStaffService.java create mode 100644 kafka-manager-extends/kafka-manager-account/src/main/java/com/xiaojukeji/kafka/manager/account/component/AbstractSingleSignOn.java create mode 100644 kafka-manager-extends/kafka-manager-account/src/main/java/com/xiaojukeji/kafka/manager/account/component/account/BaseEnterpriseStaffService.java create mode 100644 kafka-manager-extends/kafka-manager-account/src/main/java/com/xiaojukeji/kafka/manager/account/component/sso/BaseSessionSignOn.java create mode 100644 kafka-manager-extends/kafka-manager-account/src/main/java/com/xiaojukeji/kafka/manager/account/impl/AccountServiceImpl.java create mode 100644 kafka-manager-extends/kafka-manager-account/src/main/java/com/xiaojukeji/kafka/manager/account/impl/LoginServiceImpl.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/pom.xml create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/BpmService.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/Converts.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/OrderService.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/OrderResult.java rename {common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum => kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common}/OrderStatusEnum.java (80%) create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/OrderTypeEnum.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/BaseOrderDetailData.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/OrderDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/OrderExtensionApplyAppDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/OrderExtensionApplyClusterDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/OrderExtensionApplyTopicDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/OrderExtensionAuthorityDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/OrderExtensionDeleteAppDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/OrderExtensionDeleteClusterDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/OrderExtensionDeleteTopicDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/OrderExtensionModifyClusterDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/OrderExtensionQuotaDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/apply/PartitionOrderExtensionDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/AbstractOrderDetailData.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/OrderDetailApplyAppDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/OrderDetailApplyAuthorityDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/OrderDetailApplyClusterDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/OrderDetailApplyTopicDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/OrderDetailDeleteAppDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/OrderDetailDeleteAuthorityDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/OrderDetailDeleteClusterDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/OrderDetailDeleteTopicDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/OrderDetailModifyClusterDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/PartitionOrderDetailData.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/entry/detail/QuotaOrderDetailData.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/handle/OrderHandleBaseDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/handle/OrderHandleBatchDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/handle/OrderHandleQuotaDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/common/handle/OrderHandleTopicDTO.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/component/AbstractOrderStorageService.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/component/LocalStorageService.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/impl/OrderServiceImpl.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/AbstractAppOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/AbstractAuthorityOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/AbstractClusterOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/AbstractOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/AbstractTopicOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/ApplyAppOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/ApplyAuthorityOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/ApplyClusterOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/ApplyPartitionOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/ApplyQuotaOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/ApplyTopicOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/DeleteAppOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/DeleteAuthorityOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/DeleteClusterOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/DeleteTopicOrder.java create mode 100644 kafka-manager-extends/kafka-manager-bpm/src/main/java/com/xiaojukeji/kafka/manager/bpm/order/impl/ModifyClusterOrder.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/pom.xml create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/ClusterTaskService.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/KafkaFileService.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/Converters.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/bizenum/ClusterTaskActionEnum.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/bizenum/ClusterTaskStateEnum.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/bizenum/ClusterTaskSubStateEnum.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/bizenum/ClusterTaskTypeEnum.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/entry/ClusterTaskConstant.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/entry/ao/ClusterTaskStatus.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/entry/ao/ClusterTaskSubStatus.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/entry/ao/CreationTaskData.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/entry/dto/AbstractClusterTaskDTO.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/entry/dto/ClusterHostTaskDTO.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/entry/dto/ClusterRoleTaskDTO.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/common/entry/dto/ClusterTaskActionDTO.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/component/agent/AbstractAgent.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/component/agent/n9e/N9e.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/component/agent/n9e/entry/N9eResult.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/component/agent/n9e/entry/N9eTaskResultDTO.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/component/agent/n9e/entry/N9eTaskStatusEnum.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/component/agent/n9e/entry/N9eTaskStdoutDTO.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/component/storage/AbstractStorageService.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/component/storage/common/StorageEnum.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/component/storage/local/Local.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/impl/ClusterTaskServiceImpl.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/impl/KafkaFileServiceImpl.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/tasks/AbstractClusterTaskService.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/tasks/ClusterHostTaskService.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/java/com/xiaojukeji/kafka/manager/kcm/tasks/ClusterRoleTaskService.java create mode 100644 kafka-manager-extends/kafka-manager-kcm/src/main/resources/application-kcm-dev.yml create mode 100644 kafka-manager-extends/kafka-manager-monitor/pom.xml create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/MonitorService.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/MonitorSinkConstant.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/Alert.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/Metric.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/MetricSinkPoint.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/NotifyGroup.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/Silence.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/Strategy.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/StrategyAction.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/StrategyExpression.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/StrategyFilter.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/bizenum/MonitorMetricNameEnum.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/dto/MetricPoint.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/dto/MonitorRuleDTO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/dto/MonitorSilenceDTO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/dto/MonitorStrategyActionDTO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/dto/MonitorStrategyExpressionDTO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/dto/MonitorStrategyFilterDTO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/sink/MonitorBaseSinkTag.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/sink/MonitorConsumePartitionSinkTag.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/sink/MonitorConsumerSinkTag.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/sink/MonitorKafkaBaseSinkTag.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/sink/MonitorTopicPartitionSinkTag.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/sink/MonitorTopicSinkTag.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/sink/MonitorTopicThrottledSinkTag.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/vo/MonitorAlertDetailVO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/vo/MonitorAlertVO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/vo/MonitorMetricPoint.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/vo/MonitorMetricVO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/vo/MonitorNotifyGroupVO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/vo/MonitorRuleDetailVO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/vo/MonitorRuleSummaryVO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/entry/vo/MonitorSilenceVO.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/monitor/MonitorAlertDetail.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/monitor/MonitorRuleSummary.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/common/utils/CommonConverter.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/component/AbstractMonitorService.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/component/n9e/N9eConverter.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/component/n9e/N9eService.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/component/n9e/entry/N9eMetricSinkPoint.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/component/n9e/entry/N9eResult.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/java/com/xiaojukeji/kafka/manager/monitor/impl/MonitorServiceImpl.java create mode 100644 kafka-manager-extends/kafka-manager-monitor/src/main/resources/application-monitor-dev.yml create mode 100644 kafka-manager-extends/kafka-manager-notify/pom.xml create mode 100644 kafka-manager-extends/kafka-manager-notify/src/main/java/com/xiaojukeji/kafka/manager/notify/OrderApplyNotifyService.java create mode 100644 kafka-manager-extends/kafka-manager-notify/src/main/java/com/xiaojukeji/kafka/manager/notify/OrderPassedNotifyService.java create mode 100644 kafka-manager-extends/kafka-manager-notify/src/main/java/com/xiaojukeji/kafka/manager/notify/OrderRefusedNotifyService.java create mode 100644 kafka-manager-extends/kafka-manager-notify/src/main/java/com/xiaojukeji/kafka/manager/notify/common/NotifyConstant.java create mode 100644 kafka-manager-extends/kafka-manager-notify/src/main/java/com/xiaojukeji/kafka/manager/notify/common/OrderNotifyTemplate.java create mode 100644 kafka-manager-extends/kafka-manager-notify/src/main/java/com/xiaojukeji/kafka/manager/notify/notifyer/AbstractNotifyService.java create mode 100644 kafka-manager-extends/kafka-manager-notify/src/main/java/com/xiaojukeji/kafka/manager/notify/notifyer/KafkaNotifierService.java create mode 100644 kafka-manager-extends/kafka-manager-notify/src/main/resources/application-notify-dev.yml create mode 100644 kafka-manager-extends/kafka-manager-openapi/pom.xml create mode 100644 kafka-manager-task/pom.xml create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/common/BaseTaskEvent.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/common/TopicThrottledMetricsCollectedEvent.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/component/AbstractScheduledTask.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/component/BaseBizTask.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/component/CustomScheduled.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/component/EmptyEntry.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/component/Heartbeat.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/component/ScheduledTaskConstant.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/config/RegionCapacityConfig.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/config/TopicBillConfig.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/biz/CalKafkaTopicBill.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/biz/CalRegionCapacity.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/biz/CalTopicStatistics.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/biz/FlushBrokerTable.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/biz/FlushExpiredTopic.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/biz/SyncClusterTaskState.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/metrics/collect/CollectAndPublishCGData.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/metrics/collect/CollectAndPublishTopicThrottledMetrics.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/metrics/delete/DeleteMetrics.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/metrics/store/SinkCommunityTopicMetrics2Monitor.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/metrics/store/StoreBrokerMetrics.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/metrics/store/StoreCommunityTopicMetrics.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/metrics/store/StoreDiDiAppTopicMetrics.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/metrics/store/StoreDiDiTopicRequestTimeMetrics.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/op/AutoHandleTopicOrder.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/op/AutomatedHandleOrder.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/dispatch/op/FlushReassignment.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/listener/SinkCommunityTopicMetrics2Kafka.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/listener/SinkConsumerMetrics2Kafka.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/listener/SinkConsumerMetrics2Monitor.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/listener/SinkTopicThrottledMetrics2Monitor.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/listener/StoreCommunityTopicMetrics2DB.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/listener/StoreTopicThrottledMetrics2DB.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/schedule/FlushTopicMetrics.java rename service/src/main/java/com/xiaojukeji/kafka/manager/service/collector/CollectConsumerGroupBKMetadataTask.java => kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/schedule/metadata/FlushBKConsumerGroupMetadata.java (51%) create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/schedule/metadata/FlushClusterMetadata.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/schedule/metadata/FlushTopicRetentionTime.java create mode 100644 kafka-manager-task/src/main/java/com/xiaojukeji/kafka/manager/task/schedule/metadata/FlushZKConsumerGroupMetadata.java rename {web => kafka-manager-web}/pom.xml (51%) rename {web => kafka-manager-web}/src/main/java/com/xiaojukeji/kafka/manager/web/MainApplication.java (54%) create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/HealthController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/LoginController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/gateway/GatewayHeartbeatController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/gateway/GatewayReportController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/gateway/GatewaySecurityController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/gateway/GatewayServiceDiscoveryController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalAccountController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalAppController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalBillController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalClusterController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalConfigController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalConsumerController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalJmxController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalMonitorController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalOrderController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalTopicController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/normal/NormalTopicMineController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/op/OpClusterController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/op/OpClusterTaskController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/op/OpExpertController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/op/OpReassignController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/op/OpUtilsController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdAccountController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdAppController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdBillController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdBrokerController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdClusterController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdConfigController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdConsumerController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdKafkaFileController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdLogicalClusterController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdNotifyController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdOperateRecordController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdRegionController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdScheduledController.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/rd/RdTopicController.java rename {web => kafka-manager-web}/src/main/java/com/xiaojukeji/kafka/manager/web/config/DataSourceConfig.java (100%) rename {web => kafka-manager-web}/src/main/java/com/xiaojukeji/kafka/manager/web/config/SwaggerConfig.java (89%) rename {web => kafka-manager-web}/src/main/java/com/xiaojukeji/kafka/manager/web/config/WebMvcConfig.java (81%) create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/AccountConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/AppConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/BrokerModelConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/ClusterModelConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/ClusterTaskModelConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/CommonModelConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/ConfigConverter.java rename {web => kafka-manager-web}/src/main/java/com/xiaojukeji/kafka/manager/web/converters/ConsumerModelConverter.java (70%) create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/ExpertConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/GatewayModelConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/KafkaFileConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/LogicalClusterModelConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/MonitorRuleConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/OperateRecordModelConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/OrderConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/ReassignModelConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/RegionModelConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/TopicMineConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/TopicModelConverter.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/inteceptor/PermissionInterceptor.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/inteceptor/WebMetricsInterceptor.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/metrics/MetricsRegistry.java create mode 100644 kafka-manager-web/src/main/java/com/xiaojukeji/kafka/manager/web/utils/ResultCache.java create mode 100644 kafka-manager-web/src/main/resources/application.yml rename {web => kafka-manager-web}/src/main/resources/distribution/kafka-manager-springboot-distribution.xml (100%) rename {web => kafka-manager-web}/src/main/resources/logback-spring.xml (88%) delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/cache/ClusterMetadataManager.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/cache/KafkaClientCache.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/cache/KafkaMetricsCache.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/collector/BaseCollectTask.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/collector/CollectBrokerMetricsTask.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/collector/CollectConsumerGroupZKMetadataTask.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/collector/CollectConsumerMetricsTask.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/collector/CollectTopicMetricsTask.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/monitor/AbstractMonitorMatchService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/monitor/AlarmNotifyService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/monitor/AlarmRuleManager.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/monitor/AlarmScheduleCheckTask.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/monitor/impl/BrokerMonitorMatchServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/monitor/impl/ConsumerGroupMonitorMatchServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/monitor/impl/TopicMonitorMatchServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/notify/KafkaNotifier.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/schedule/ScheduleCollectDataManager.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/schedule/ScheduleDeleteMetrics.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/schedule/ScheduleStoreMetrics.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/schedule/ScheduleTriggerTopicReassignmentTask.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/AdminPreferredReplicaElectService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/AdminTopicService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/AlarmRuleService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/BrokerService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/ClusterService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/ConsumerService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/JmxService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/LoginService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/MigrationService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/OrderService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/RegionService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/TopicManagerService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/TopicService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/ZookeeperService.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/AdminPreferredReplicaElectServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/AdminTopicServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/AlarmRuleServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/BrokerServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/ClusterServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/JmxServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/LoginServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/MigrationServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/OrderServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/RegionServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/TopicManagerServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/TopicServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/service/impl/ZookeeperServiceImpl.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/utils/BrokerMetadataUtil.java delete mode 100644 service/src/main/java/com/xiaojukeji/kafka/manager/service/utils/ObjectUtil.java delete mode 100644 web/bin/shutdown.sh delete mode 100644 web/bin/startup.sh delete mode 100644 web/conf/application.yml delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/AdminAccountController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/AdminMigrationController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/AdminRebalanceController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/AdminRegionController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/AdminUtilsController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/AlarmController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/BrokerController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/ClusterController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/ConsumerController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/LoginController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/OrderController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/api/versionone/TopicController.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/AccountConverter.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/AdminMigrationConverter.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/AdminUtilConverter.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/AlarmConverter.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/BrokerModelConverter.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/ClusterModelConverter.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/OrderConverter.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/RegionModelConverter.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/converters/TopicModelConverter.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/inteceptor/PermissionInterceptor.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/inteceptor/WebMetricsInterceptor.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/ClusterModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/MigrationCreateModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/MigrationModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/OffsetResetModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/alarm/AlarmRuleModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/order/OrderPartitionExecModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/order/OrderPartitionModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/order/OrderTopicExecModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/order/OrderTopicModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/AdminTopicModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/TopicDataSampleModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/TopicDeleteModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/TopicFavoriteModel.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/AccountVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/KafkaControllerVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/MigrationDetailVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/PartitionReassignmentVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/alarm/AlarmConstantVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/alarm/AlarmRuleVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerKeyMetricsVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerOverallVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerOverviewVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerStatusVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/cluster/ClusterMetricsVO.java delete mode 100644 web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicMetadataVO.java delete mode 100644 web/src/main/resources/application-pg.yml delete mode 100644 web/src/main/resources/application.yml delete mode 100644 web/src/main/resources/assembly.xml diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 6bfaadea..00000000 --- a/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM fabric8/java-alpine-openjdk8-jdk -MAINTAINER xuzhengxi -ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 -ADD ./web/target/kafka-manager-web-1.1.0-SNAPSHOT.jar kafka-manager-web.jar -ADD ./docker/kafka-manager/application-standalone.yml application.yml -ENTRYPOINT ["java","-jar","/kafka-manager-web.jar","--spring.config.location=./application.yml"] -EXPOSE 8080 \ No newline at end of file diff --git a/README.md b/README.md index e65dc2c0..bcbad513 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ --- -![kafka-manager-logo](doc/assets/images/common/logo_name.png) +![kafka-manager-logo](./docs/assets/images/common/logo_name.png) **一站式`Apache Kafka`集群指标监控与运维管控平台** @@ -12,110 +12,39 @@ ### 集群监控维度 -- 多版本集群管控,支持从`0.10.2`到`2.4`版本; +- 多版本集群管控,支持从`0.10.2`到`2.x`版本; - 集群Topic、Broker等多维度历史与实时关键指标查看; ### 集群管控维度 -- 集群运维,包括逻辑Region方式管理集群; -- Broker运维,包括优先副本选举; +- 集群运维,包括逻辑Region方式管理集群 +- Broker运维,包括优先副本选举 - Topic运维,包括创建、查询、扩容、修改属性、数据采样及迁移等; -- 消费组运维,包括指定时间或指定偏移两种方式进行重置消费偏移; +- 消费组运维,包括指定时间或指定偏移两种方式进行重置消费偏移 ### 用户使用维度 -- 管理员用户与普通用户视角区分; -- 管理员用户与普通用户权限区分; +- Kafka用户、Kafka研发、Kafka运维 视角区分 +- Kafka用户、Kafka研发、Kafka运维 权限区分 ---- ## kafka-manager架构图 -![kafka-manager-arch](doc/assets/images/common/arch.png) +![kafka-manager-arch](./docs/assets/images/common/arch.png) ---- - -## 安装手册 - -### 环境依赖 - -- `Maven 3.5.0+`(后端打包依赖) -- `node v8.12.0+`(前端打包依赖) -- `Java 8+`(运行环境需要) -- `MySQL` 或 `PostgreSQL`(数据存储) - ---- - -### 环境初始化 - -**MySQL** - -执行[create_mysql_table.sql](doc/create_mysql_table.sql)中的SQL命令,从而创建所需的MySQL库及表,默认创建的库名是`kafka_manager`。 - -``` -############# 示例: -mysql -uXXXX -pXXX -h XXX.XXX.XXX.XXX -PXXXX < ./create_mysql_table.sql -``` - -**PostgreSQL** - -执行[create_postgresql_table.sql](doc/create_postgresql_table.sql)中的SQL命令,从而创建所需的PostgreSQL表。 - -``` -############# 示例: -psql -h XXX.XXX.XXX.XXX -U XXXX -d kafka_manager -f ./create_postgresql_table.sql -``` - -*PostgreSQL 用户、数据库创建方式* - -```sql -create user admin encrypted password 'admin'; -create database kafka_manager owner=admin template=template0 encoding='UTF-8' lc_collate='zh_CN.UTF-8' lc_ctype='zh_CN.UTF-8'; -``` - -***默认配置使用 MySQL 数据库,若要使用 PostgreSQL 数据库,使用 `-Dspring.profiles.active=pg` 指定 `application-pg.yml` 配置文件。*** - ---- - - -### 打包 - -执行`mvn install`命令即可。 - -备注:每一次执行`mvn install`命令,都将在`web/src/main/resources/templates`下面生成最新的前端资源文件,如果`console`模块下的代码没有变更,可以修改`./pom.xml`文件,忽略对`console`模块的打包。 - ---- - -### 启动 - -``` -############# application.yml 是配置文件 -cp web/src/main/resources/application.yml web/target/ -cd web/target/ -nohup java -jar kafka-manager-web-1.1.0-SNAPSHOT.jar --spring.config.location=./application.yml > /dev/null 2>&1 & -``` - -### 使用 - -本地启动的话,访问`http://localhost:8080`,输入帐号及密码进行登录。更多参考:[kafka-manager使用手册](doc/user_cn_guide.md) - - ---- - ## 相关文档 -- [kafka-manager使用手册](doc/user_cn_guide.md) +- [kafka-manager安装手册](./docs/install_cn_guide.md) +- [kafka-manager接入集群](./docs/manual_kafka_op/add_cluster.md) +- [kafka-manager使用手册-待更新](./docs/user_cn_guide.md) ## 钉钉交流群 -搜索群号:`32821440` 或者扫码可入群交流. 备注:在钉钉搜索框搜索`32821440`,然后搜索结果中点击 "网络查找手机/邮箱/钉钉号" 即可看到我们的钉钉群:滴滴KafkaManager开源用户群。 - - -![dingding_group](doc/assets/images/common/dingding_group.jpg) +![dingding_group](./docs/assets/images/common/dingding_group.jpg) ## 项目成员 diff --git a/common/pom.xml b/common/pom.xml deleted file mode 100644 index a39bcd31..00000000 --- a/common/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - 4.0.0 - com.xiaojukeji.kafka - kafka-manager-common - 1.1.0-SNAPSHOT - jar - - - kafka-manager - com.xiaojukeji.kafka - 1.1.0-SNAPSHOT - - - - 1.0.0-SNAPSHOT - true - true - 1.8 - 1.8 - UTF-8 - UTF-8 - - - - commons-beanutils - commons-beanutils - 1.9.3 - - - org.apache.curator - curator-recipes - 2.10.0 - - - org.apache.zookeeper - zookeeper - - - com.alibaba - fastjson - - - org.apache.kafka - kafka_2.10 - - - \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/Constant.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/Constant.java deleted file mode 100644 index fc6a657e..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/Constant.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.constant; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * @author zengqiao - * @date 20/2/28 - */ -public class Constant { - public static final String KAFKA_MANAGER_INNER_ERROR = "kafka-manager inner error"; - - public final static Map> BROKER_METRICS_TYPE_MBEAN_NAME_MAP = new ConcurrentHashMap<>(); - - public final static Map> TOPIC_METRICS_TYPE_MBEAN_NAME_MAP = new ConcurrentHashMap<>(); - - public static final String COLLECTOR_METRICS_LOGGER = "COLLECTOR_METRICS_LOGGER"; - - public static final String API_METRICS_LOGGER = "API_METRICS_LOGGER"; -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/MetricsType.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/MetricsType.java deleted file mode 100644 index 290330bf..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/MetricsType.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.constant; - -public class MetricsType { - /** - * Broker流量详情 - */ - public static final int BROKER_FLOW_DETAIL = 0; - public static final int BROKER_TO_DB_METRICS = 1; // Broker入DB的Metrics指标 - public static final int BROKER_REAL_TIME_METRICS = 2; // Broker入DB的Metrics指标 - public static final int BROKER_OVER_VIEW_METRICS = 3; // Broker状态概览的指标 - public static final int BROKER_OVER_ALL_METRICS = 4; // Broker状态总揽的指标 - public static final int BROKER_ANALYSIS_METRICS = 5; // Broker分析的指标 - public static final int BROKER_TOPIC_ANALYSIS_METRICS = 6; // Broker分析的指标 - - /** - * Topic流量详情 - */ - public static final int TOPIC_FLOW_DETAIL = 100; - public static final int TOPIC_FLOW_OVERVIEW = 101; - public static final int TOPIC_METRICS_TO_DB = 102; - - -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/OffsetStoreLocation.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/OffsetStoreLocation.java deleted file mode 100644 index b1cd29f7..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/OffsetStoreLocation.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.constant; - -/** - * @author limeng - * @date 2017/11/21 - */ -public enum OffsetStoreLocation { - - ZOOKEEPER("zookeeper"), - - BROKER("broker"); - - private final String location; - - OffsetStoreLocation(String location) { - this.location = location; - } - - public String getLocation() { - return location; - } - - public static OffsetStoreLocation getOffsetStoreLocation(String location) { - if (location == null) { - return null; - } - - for (OffsetStoreLocation offsetStoreLocation: OffsetStoreLocation.values()) { - if (offsetStoreLocation.location.equals(location)) { - return offsetStoreLocation; - } - } - return null; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/StatusCode.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/StatusCode.java deleted file mode 100644 index f56ad7dc..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/StatusCode.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.constant; - -public class StatusCode { - /* - * kafka-manager status code: 17000 ~ 17999 - * - * 正常 - 0 - * 参数错误 - 10000 - * 资源未就绪 - 10001 - */ - - /* - * 已约定的状态码 - */ - public static final Integer SUCCESS = 0; - public static final Integer PARAM_ERROR = 10000; //参数错误 - public static final Integer RES_UNREADY = 10001; //资源未就绪 - - public static final Integer MY_SQL_SELECT_ERROR = 17210; // MySQL 查询数据异常 - public static final Integer MY_SQL_INSERT_ERROR = 17211; // MySQL 插入数据异常 - public static final Integer MY_SQL_DELETE_ERROR = 17212; // MySQL 删除数据异常 - public static final Integer MY_SQL_UPDATE_ERROR = 17213; // MySQL 更新数据异常 - public static final Integer MY_SQL_REPLACE_ERROR = 17214; // MySQL 替换数据异常 - - public static final Integer OPERATION_ERROR = 17300; // 请求操作异常 - - - /** - * Topic相关的异常 - */ - public static final Integer TOPIC_EXISTED = 17400; //Topic已经存在了 - - public static final Integer PARTIAL_SUCESS = 17700; //操作部分成功 - -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorConditionType.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorConditionType.java deleted file mode 100644 index 2b48dde4..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorConditionType.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.constant.monitor; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.List; - -/** - * 条件类型 - * @author zengqiao - * @date 19/5/12 - */ -public enum MonitorConditionType { - BIGGER(">", "大于"), - EQUAL("=", "等于"), - LESS("<", "小于"), - NOT_EQUAL("!=", "不等于"); - - private String name; - - private String message; - - MonitorConditionType(String name, String message) { - this.name = name; - this.message = message; - } - - public static boolean legal(String name) { - for (MonitorConditionType elem: MonitorConditionType.values()) { - if (elem.name.equals(name)) { - return true; - } - } - return false; - } - - @Override - public String toString() { - return "ConditionType{" + - "name='" + name + '\'' + - ", message='" + message + '\'' + - '}'; - } - - public static List> toList() { - List> conditionTypeList = new ArrayList<>(); - for (MonitorConditionType elem: MonitorConditionType.values()) { - conditionTypeList.add(new AbstractMap.SimpleEntry<>(elem.name, elem.message)); - } - return conditionTypeList; - } - - /** - * 计算 operation(data1, data2) 是否为true - * @param data1 - * @param data2 - * @param operation - * @author zengqiao - * @date 19/5/12 - * @return boolean - */ - public static boolean matchCondition(Double data1, Double data2, String operation) { - switch (operation) { - case ">": return data1 > data2; - case "<": return data1 < data2; - case "=": return data1.equals(data2); - case "!=": return !data1.equals(data2); - default: - } - return false; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorMatchStatus.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorMatchStatus.java deleted file mode 100644 index 5ab3dd5d..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorMatchStatus.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.constant.monitor; - -/** - * @author zengqiao - * @date 20/3/18 - */ -public enum MonitorMatchStatus { - UNKNOWN(0), - - YES(1), - - NO(2); - - public Integer status; - - MonitorMatchStatus(Integer status) { - this.status = status; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorMetricsType.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorMetricsType.java deleted file mode 100644 index 1611c55c..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorMetricsType.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.constant.monitor; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.List; - -/** - * 指标类型 - * @author zengqiao - * @date 19/5/12 - */ -public enum MonitorMetricsType { - BYTES_IN("BytesIn", "流入流量"), - BYTES_OUT("BytesOut", "流出流量"), - LAG("Lag", "消费组Lag"); - - private String name; - - private String message; - - MonitorMetricsType(String name, String message) { - this.name = name; - this.message = message; - } - - public static boolean legal(String name) { - for (MonitorMetricsType elem: MonitorMetricsType.values()) { - if (elem.name.equals(name)) { - return true; - } - } - return false; - } - - @Override - public String toString() { - return "MetricType{" + - "name='" + name + '\'' + - ", message='" + message + '\'' + - '}'; - } - - public static List> toList() { - List> metricTypeList = new ArrayList<>(); - for (MonitorMetricsType elem: MonitorMetricsType.values()) { - metricTypeList.add(new AbstractMap.SimpleEntry<>(elem.name, elem.message)); - } - return metricTypeList; - } - - public String getName() { - return name; - } - - public String getMessage() { - return message; - } - -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorNotifyType.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorNotifyType.java deleted file mode 100644 index d71cda56..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/monitor/MonitorNotifyType.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.constant.monitor; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.List; - -/** - * 通知类型 - * @author huangyiminghappy@163.com - * @date 2019-05-06 - */ -public enum MonitorNotifyType { - KAFKA_MESSAGE("KAFKA", "告警发送到KAFKA"); - - String name; - - String message; - - MonitorNotifyType(String name, String message){ - this.name = name; - this.message = message; - } - - public String getName() { - return name; - } - - public String getMessage() { - return message; - } - - public static boolean legal(String name) { - for (MonitorNotifyType elem: MonitorNotifyType.values()) { - if (elem.name.equals(name)) { - return true; - } - } - return false; - } - - @Override - public String toString() { - return "NotifyType{" + - "name='" + name + '\'' + - ", message='" + message + '\'' + - '}'; - } - - public static List> toList() { - List> notifyTypeList = new ArrayList<>(); - for (MonitorNotifyType elem: MonitorNotifyType.values()) { - notifyTypeList.add(new AbstractMap.SimpleEntry<>(elem.name, elem.message)); - } - return notifyTypeList; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetrics.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetrics.java deleted file mode 100644 index d16cb338..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetrics.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity; - -/** - * ConsumerMetrics - * @author tukun - * @date 2015/11/12 - */ -public class ConsumerMetrics { - private Long clusterId; - - private String topicName; - - private String consumerGroup; - - private String location; - - private Long sumLag; - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - public String getConsumerGroup() { - return consumerGroup; - } - - public void setConsumerGroup(String consumerGroup) { - this.consumerGroup = consumerGroup; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - public Long getSumLag() { - return sumLag; - } - - public void setSumLag(Long sumLag) { - this.sumLag = sumLag; - } - - @Override - public String toString() { - return "ConsumerMetrics{" + - "clusterId=" + clusterId + - ", topicName='" + topicName + '\'' + - ", consumerGroup='" + consumerGroup + '\'' + - ", location='" + location + '\'' + - ", sumLag=" + sumLag + - '}'; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/annotations/FieldSelector.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/annotations/FieldSelector.java deleted file mode 100644 index 722f20f3..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/annotations/FieldSelector.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.annotations; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * FieldSelector - * @author huangyiminghappy@163.com - * @date 2019-06-19 - */ -@Target(ElementType.FIELD) -@Retention(RUNTIME) -@Documented -public @interface FieldSelector { - //注解的属性 - String name() default ""; - - int[] types() default {}; - -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/AccountRoleEnum.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/AccountRoleEnum.java deleted file mode 100644 index c1c4a769..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/AccountRoleEnum.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.bizenum; - -/** - * 用户角色 - * @author zengqiao_cn@163.com - * @date 19/4/15 - */ -public enum AccountRoleEnum { - UNKNOWN(-1), - - NORMAL(0), - - SRE(1), - - ADMIN(2); - - private Integer role; - - AccountRoleEnum(Integer role) { - this.role = role; - } - - public Integer getRole() { - return role; - } - - public static AccountRoleEnum getUserRoleEnum(Integer role) { - for (AccountRoleEnum elem: AccountRoleEnum.values()) { - if (elem.getRole().equals(role)) { - return elem; - } - } - return null; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/AdminTopicStatusEnum.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/AdminTopicStatusEnum.java deleted file mode 100644 index 883648e4..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/AdminTopicStatusEnum.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.bizenum; - -/** - * 操作Topic的状态 - * @author zengqiao - * @date 19/11/26 - */ -public enum AdminTopicStatusEnum { - SUCCESS(0, "成功"), - REPLACE_DB_FAILED(1, "更新DB失败"), - PARAM_NULL_POINTER(2, "参数错误"), - PARTITION_NUM_ILLEGAL(3, "分区数错误"), - BROKER_NUM_NOT_ENOUGH(4, "Broker数不足错误"), - TOPIC_NAME_ILLEGAL(5, "Topic名称非法"), - TOPIC_EXISTED(6, "Topic已存在"), - UNKNOWN_TOPIC_PARTITION(7, "Topic未知"), - TOPIC_CONFIG_ILLEGAL(8, "Topic配置错误"), - TOPIC_IN_DELETING(9, "Topic正在删除"), - UNKNOWN_ERROR(10, "未知错误"); - - private Integer code; - - private String message; - - AdminTopicStatusEnum(Integer code, String message) { - this.code = code; - this.message = message; - } - - public Integer getCode() { - return code; - } - - public String getMessage() { - return message; - } -} - diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/DBStatusEnum.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/DBStatusEnum.java deleted file mode 100644 index 6cd66544..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/DBStatusEnum.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.bizenum; - -/** - * DBStatus状态含义 - * @author zengqiao_cn@163.com - * @date 19/4/15 - */ -public enum DBStatusEnum { - /** - * 逻辑删除 - */ - DELETED(-1), - - /** - * 普通 - */ - NORMAL(0), - - /** - * 已完成并通过 - */ - PASSED(1); - - private Integer status; - - DBStatusEnum(Integer status) { - this.status = status; - } - - public Integer getStatus() { - return status; - } - - public static DBStatusEnum getDBStatusEnum(Integer status) { - for (DBStatusEnum elem: DBStatusEnum.values()) { - if (elem.getStatus().equals(status)) { - return elem; - } - } - return null; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/OperationEnum.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/OperationEnum.java deleted file mode 100644 index 6061b81c..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/OperationEnum.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.bizenum; - -/** - * 操作类型 - * @author zengqiao - * @date 19/11/21 - */ -public enum OperationEnum { - CREATE_TOPIC("create_topic"), - DELETE_TOPIC("delete_topic"), - MODIFY_TOPIC_CONFIG("modify_topic_config"), - EXPAND_TOPIC_PARTITION("expand_topic_partition"); - - public String message; - - OperationEnum(String message) { - this.message = message; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/OrderTypeEnum.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/OrderTypeEnum.java deleted file mode 100644 index 70de82b4..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/OrderTypeEnum.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.bizenum; - -/** - * 工单类型 - * @author zengqiao - * @date 19/6/23 - */ -public enum OrderTypeEnum { - UNKNOWN(-1), - - APPLY_TOPIC(0), - - APPLY_PARTITION(1); - - private Integer code; - - OrderTypeEnum(Integer code) { - this.code = code; - } - - public Integer getCode() { - return code; - } - - public static OrderTypeEnum getOrderTypeEnum(Integer code) { - for (OrderTypeEnum elem: OrderTypeEnum.values()) { - if (elem.getCode().equals(code)) { - return elem; - } - } - return OrderTypeEnum.UNKNOWN; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/PreferredReplicaElectEnum.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/PreferredReplicaElectEnum.java deleted file mode 100644 index ade9bb8f..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/PreferredReplicaElectEnum.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.bizenum; - -/** - * 优先副本选举状态 - * @author zengqiao - * @date 2017/6/29. - */ -public enum PreferredReplicaElectEnum { - SUCCESS(0, "成功[创建成功|执行成功]"), - RUNNING(1, "正在执行"), - ALREADY_EXIST(2, "任务已存在"), - PARAM_ILLEGAL(3, "参数错误"), - UNKNOWN(4, "进度未知"); - - private Integer code; - - private String message; - - PreferredReplicaElectEnum(Integer code, String message) { - this.code = code; - this.message = message; - } - - public Integer getCode() { - return code; - } - - public String getMessage() { - return message; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/ReassignmentStatusEnum.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/ReassignmentStatusEnum.java deleted file mode 100644 index 1bb892db..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/bizenum/ReassignmentStatusEnum.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.bizenum; - -/** - * 迁移状态 - * @author zengqiao - * @date 19/12/29 - */ -public enum ReassignmentStatusEnum { - WAITING(0, "等待执行"), - RUNNING(1, "正在执行"), - SUCCESS(2, "迁移成功"), - FAILED(3, "迁移失败"), - CANCELED(4, "取消任务"); - - private Integer code; - - private String message; - - ReassignmentStatusEnum(Integer code, String message) { - this.code = code; - this.message = message; - } - - public Integer getCode() { - return code; - } - - public String getMessage() { - return message; - } - - public static boolean triggerTask(Integer status) { - if (WAITING.code.equals(status) || RUNNING.code.equals(status)) { - return true; - } - return false; - } - - public static boolean cancelTask(Integer status) { - if (WAITING.code.equals(status)) { - return true; - } - return false; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerOverallDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerOverallDTO.java deleted file mode 100644 index 07243d48..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerOverallDTO.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto; - -import com.xiaojukeji.kafka.manager.common.entity.metrics.BrokerMetrics; -import com.xiaojukeji.kafka.manager.common.entity.zookeeper.BrokerMetadata; - -/** - * @author zengqiao - * @date 19/4/21 - */ -public class BrokerOverallDTO { - private Integer brokerId; - - private String host; - - private Integer port; - - private Integer jmxPort; - - private Long startTime; - - private Integer partitionCount; - - private Integer underReplicatedPartitions; - - private Integer leaderCount; - - private Double bytesInPerSec; - - public Integer getBrokerId() { - return brokerId; - } - - public void setBrokerId(Integer brokerId) { - this.brokerId = brokerId; - } - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public Integer getPort() { - return port; - } - - public void setPort(Integer port) { - this.port = port; - } - - public Integer getJmxPort() { - return jmxPort; - } - - public void setJmxPort(Integer jmxPort) { - this.jmxPort = jmxPort; - } - - public Long getStartTime() { - return startTime; - } - - public void setStartTime(Long startTime) { - this.startTime = startTime; - } - - public Integer getPartitionCount() { - return partitionCount; - } - - public void setPartitionCount(Integer partitionCount) { - this.partitionCount = partitionCount; - } - - public Integer getUnderReplicatedPartitions() { - return underReplicatedPartitions; - } - - public void setUnderReplicatedPartitions(Integer underReplicatedPartitions) { - this.underReplicatedPartitions = underReplicatedPartitions; - } - - public Integer getLeaderCount() { - return leaderCount; - } - - public void setLeaderCount(Integer leaderCount) { - this.leaderCount = leaderCount; - } - - public Double getBytesInPerSec() { - return bytesInPerSec; - } - - public void setBytesInPerSec(Double bytesInPerSec) { - this.bytesInPerSec = bytesInPerSec; - } - - @Override - public String toString() { - return "BrokerOverallDTO{" + - "brokerId=" + brokerId + - ", host='" + host + '\'' + - ", port=" + port + - ", jmxPort=" + jmxPort + - ", startTime=" + startTime + - ", partitionCount=" + partitionCount + - ", underReplicatedPartitions=" + underReplicatedPartitions + - ", leaderCount=" + leaderCount + - ", bytesInPerSec=" + bytesInPerSec + - '}'; - } - - public static BrokerOverallDTO newInstance(BrokerMetadata brokerMetadata, BrokerMetrics brokerMetrics) { - BrokerOverallDTO brokerOverallDTO = new BrokerOverallDTO(); - brokerOverallDTO.setBrokerId(brokerMetadata.getBrokerId()); - brokerOverallDTO.setHost(brokerMetadata.getHost()); - brokerOverallDTO.setPort(brokerMetadata.getPort()); - brokerOverallDTO.setJmxPort(brokerMetadata.getJmxPort()); - brokerOverallDTO.setStartTime(brokerMetadata.getTimestamp()); - if (brokerMetrics == null) { - return brokerOverallDTO; - } - brokerOverallDTO.setPartitionCount(brokerMetrics.getPartitionCount()); - brokerOverallDTO.setLeaderCount(brokerMetrics.getLeaderCount()); - brokerOverallDTO.setBytesInPerSec(brokerMetrics.getBytesInPerSec()); - brokerOverallDTO.setUnderReplicatedPartitions(brokerMetrics.getUnderReplicatedPartitions()); - return brokerOverallDTO; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerOverviewDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerOverviewDTO.java deleted file mode 100644 index 18ca0eb5..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerOverviewDTO.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto; - -import com.xiaojukeji.kafka.manager.common.entity.metrics.BrokerMetrics; -import com.xiaojukeji.kafka.manager.common.entity.zookeeper.BrokerMetadata; -import com.xiaojukeji.kafka.manager.common.entity.bizenum.DBStatusEnum; - -/** - * @author zengqiao_cn@163.com - * @date 19/4/21 - */ -public class BrokerOverviewDTO { - private Integer brokerId; - - private String host; - - private Integer port; - - private Integer jmxPort; - - private Long startTime; - - private Double byteIn; - - private Double byteOut; - - private Integer status; - - public Integer getBrokerId() { - return brokerId; - } - - public void setBrokerId(Integer brokerId) { - this.brokerId = brokerId; - } - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public Integer getPort() { - return port; - } - - public void setPort(Integer port) { - this.port = port; - } - - public Integer getJmxPort() { - return jmxPort; - } - - public void setJmxPort(Integer jmxPort) { - this.jmxPort = jmxPort; - } - - public Long getStartTime() { - return startTime; - } - - public void setStartTime(Long startTime) { - this.startTime = startTime; - } - - public Double getByteIn() { - return byteIn; - } - - public void setByteIn(Double byteIn) { - this.byteIn = byteIn; - } - - public Double getByteOut() { - return byteOut; - } - - public void setByteOut(Double byteOut) { - this.byteOut = byteOut; - } - - public Integer getStatus() { - return status; - } - - public void setStatus(Integer status) { - this.status = status; - } - - @Override - public String toString() { - return "BrokerInfoDTO{" + - "brokerId=" + brokerId + - ", host='" + host + '\'' + - ", port=" + port + - ", jmxPort=" + jmxPort + - ", startTime=" + startTime + - ", byteIn=" + byteIn + - ", byteOut=" + byteOut + - ", status=" + status + - '}'; - } - - public static BrokerOverviewDTO newInstance(BrokerMetadata brokerMetadata, BrokerMetrics brokerMetrics) { - BrokerOverviewDTO brokerOverviewDTO = new BrokerOverviewDTO(); - brokerOverviewDTO.setBrokerId(brokerMetadata.getBrokerId()); - brokerOverviewDTO.setHost(brokerMetadata.getHost()); - brokerOverviewDTO.setPort(brokerMetadata.getPort()); - brokerOverviewDTO.setJmxPort(brokerMetadata.getJmxPort()); - brokerOverviewDTO.setStartTime(brokerMetadata.getTimestamp()); - brokerOverviewDTO.setStatus(DBStatusEnum.NORMAL.getStatus()); - if (brokerMetrics == null) { - return brokerOverviewDTO; - } - brokerOverviewDTO.setByteIn(brokerMetrics.getBytesInPerSec()); - brokerOverviewDTO.setByteOut(brokerMetrics.getBytesOutPerSec()); - return brokerOverviewDTO; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/ControllerDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/ControllerDTO.java deleted file mode 100644 index c798e79f..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/ControllerDTO.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto; - -import java.util.Date; - -/** - * @author zengqiao - * @date 19/4/22 - */ -public class ControllerDTO { - private String clusterName; - - private Integer brokerId; - - private String host; - - private Integer controllerVersion; - - private Date controllerTimestamp; - - public String getClusterName() { - return clusterName; - } - - public void setClusterName(String clusterName) { - this.clusterName = clusterName; - } - - public Integer getBrokerId() { - return brokerId; - } - - public void setBrokerId(Integer brokerId) { - this.brokerId = brokerId; - } - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public Integer getControllerVersion() { - return controllerVersion; - } - - public void setControllerVersion(Integer controllerVersion) { - this.controllerVersion = controllerVersion; - } - - public Date getControllerTimestamp() { - return controllerTimestamp; - } - - public void setControllerTimestamp(Date controllerTimestamp) { - this.controllerTimestamp = controllerTimestamp; - } - - @Override - public String toString() { - return "ControllerInfoDTO{" + - "clusterName='" + clusterName + '\'' + - ", brokerId=" + brokerId + - ", host='" + host + '\'' + - ", controllerVersion=" + controllerVersion + - ", controllerTimestamp=" + controllerTimestamp + - '}'; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicBasicDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicBasicDTO.java deleted file mode 100644 index e8f4e1c1..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicBasicDTO.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto; - -/** - * @author arthur - * @date 2018/09/03 - */ -public class TopicBasicDTO { - private String topicName; - - private Integer partitionNum; - - private Integer replicaNum; - - private Integer brokerNum; - - private String remark; - - private Long modifyTime; - - private Long createTime; - - private String region; - - private Long retentionTime; - - private String principal; - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - public Integer getPartitionNum() { - return partitionNum; - } - - public void setPartitionNum(Integer partitionNum) { - this.partitionNum = partitionNum; - } - - public Integer getReplicaNum() { - return replicaNum; - } - - public void setReplicaNum(Integer replicaNum) { - this.replicaNum = replicaNum; - } - - public Integer getBrokerNum() { - return brokerNum; - } - - public void setBrokerNum(Integer brokerNum) { - this.brokerNum = brokerNum; - } - - public String getRemark() { - return remark; - } - - public void setRemark(String remark) { - this.remark = remark; - } - - public String getRegion() { - return region; - } - - public void setRegion(String region) { - this.region = region; - } - - public Long getRetentionTime() { - return retentionTime; - } - - public void setRetentionTime(Long retentionTime) { - this.retentionTime = retentionTime; - } - - public Long getModifyTime() { - return modifyTime; - } - - public void setModifyTime(Long modifyTime) { - this.modifyTime = modifyTime; - } - - public Long getCreateTime() { - return createTime; - } - - public void setCreateTime(Long createTime) { - this.createTime = createTime; - } - - public String getPrincipal() { - return principal; - } - - public void setPrincipal(String principal) { - this.principal = principal; - } - - @Override - public String toString() { - return "TopicBasicInfoDTO{" + - "topicName='" + topicName + '\'' + - ", partitionNum=" + partitionNum + - ", replicaNum=" + replicaNum + - ", brokerNum=" + brokerNum + - ", remark='" + remark + '\'' + - ", modifyTime=" + modifyTime + - ", createTime=" + createTime + - ", region='" + region + '\'' + - ", retentionTime=" + retentionTime + - ", principal='" + principal + '\'' + - '}'; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicOverviewDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicOverviewDTO.java deleted file mode 100644 index 80647dea..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicOverviewDTO.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto; - -public class TopicOverviewDTO { - private Long clusterId; - - private String topicName; - - private Integer replicaNum; - - private Integer partitionNum; - - private Double bytesInPerSec; - - private Double produceRequestPerSec; - - private Long updateTime; - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - public Integer getReplicaNum() { - return replicaNum; - } - - public void setReplicaNum(Integer replicaNum) { - this.replicaNum = replicaNum; - } - - public Integer getPartitionNum() { - return partitionNum; - } - - public void setPartitionNum(Integer partitionNum) { - this.partitionNum = partitionNum; - } - - public Double getBytesInPerSec() { - return bytesInPerSec; - } - - public void setBytesInPerSec(Double bytesInPerSec) { - this.bytesInPerSec = bytesInPerSec; - } - - public Double getProduceRequestPerSec() { - return produceRequestPerSec; - } - - public void setProduceRequestPerSec(Double produceRequestPerSec) { - this.produceRequestPerSec = produceRequestPerSec; - } - - public Long getUpdateTime() { - return updateTime; - } - - public void setUpdateTime(Long updateTime) { - this.updateTime = updateTime; - } - - @Override - public String toString() { - return "TopicOverviewDTO{" + - "clusterId=" + clusterId + - ", topicName='" + topicName + '\'' + - ", replicaNum=" + replicaNum + - ", partitionNum=" + partitionNum + - ", bytesInPerSec=" + bytesInPerSec + - ", produceRequestPerSec=" + produceRequestPerSec + - ", updateTime=" + updateTime + - '}'; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicPartitionDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicPartitionDTO.java deleted file mode 100644 index 154ca694..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/TopicPartitionDTO.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto; - -import java.io.Serializable; -import java.util.List; - -/** - * @author arthur - * @date 2017/6/6. - */ -public class TopicPartitionDTO implements Serializable { - - private Integer partitionId; - - private Long offset; - - private Integer leaderBrokerId; - - private Integer preferredBrokerId; - - private Integer leaderEpoch; - - private List replicasBroker; - - private List isr; - - private Boolean underReplicated; - - public Integer getPartitionId() { - return partitionId; - } - - public void setPartitionId(Integer partitionId) { - this.partitionId = partitionId; - } - - public Long getOffset() { - return offset; - } - - public void setOffset(Long offset) { - this.offset = offset; - } - - public Integer getLeaderBrokerId() { - return leaderBrokerId; - } - - public void setLeaderBrokerId(Integer leaderBrokerId) { - this.leaderBrokerId = leaderBrokerId; - } - - public Integer getPreferredBrokerId() { - return preferredBrokerId; - } - - public void setPreferredBrokerId(Integer preferredBrokerId) { - this.preferredBrokerId = preferredBrokerId; - } - - public Integer getLeaderEpoch() { - return leaderEpoch; - } - - public void setLeaderEpoch(Integer leaderEpoch) { - this.leaderEpoch = leaderEpoch; - } - - public List getReplicasBroker() { - return replicasBroker; - } - - public void setReplicasBroker(List replicasBroker) { - this.replicasBroker = replicasBroker; - } - - public List getIsr() { - return isr; - } - - public void setIsr(List isr) { - this.isr = isr; - } - - public boolean isUnderReplicated() { - return underReplicated; - } - - public void setUnderReplicated(boolean underReplicated) { - this.underReplicated = underReplicated; - } - - @Override - public String toString() { - return "TopicPartitionDTO{" + - "partitionId=" + partitionId + - ", offset=" + offset + - ", leaderBrokerId=" + leaderBrokerId + - ", preferredBrokerId=" + preferredBrokerId + - ", leaderEpoch=" + leaderEpoch + - ", replicasBroker=" + replicasBroker + - ", isr=" + isr + - ", underReplicated=" + underReplicated + - '}'; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmNotifyDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmNotifyDTO.java deleted file mode 100644 index 01b6497c..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmNotifyDTO.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto.alarm; - -/** - * 告警通知 - * @author zengqiao - * @date 2020-02-14 - */ -public class AlarmNotifyDTO { - private Long alarmRuleId; - - private String actionTag; - - private String message; - - public Long getAlarmRuleId() { - return alarmRuleId; - } - - public void setAlarmRuleId(Long alarmRuleId) { - this.alarmRuleId = alarmRuleId; - } - - public String getActionTag() { - return actionTag; - } - - public void setActionTag(String actionTag) { - this.actionTag = actionTag; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - @Override - public String toString() { - return "AlarmNotifyDTO{" + - "alarmRuleId=" + alarmRuleId + - ", actionTag='" + actionTag + '\'' + - ", message='" + message + '\'' + - '}'; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmRuleDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmRuleDTO.java deleted file mode 100644 index 8fab24c4..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmRuleDTO.java +++ /dev/null @@ -1,127 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto.alarm; - -import java.util.Map; - -/** - * @author zengqiao - * @date 19/12/16 - */ -public class AlarmRuleDTO { - /** - * 告警ID - */ - private Long id; - - /** - * 告警名称 - */ - private String name; - - /** - * 已持续次数 - */ - private Integer duration; - - /** - * 集群ID, 过滤条件中必有的, 单独拿出来 - */ - private Long clusterId; - - /** - * 告警策略表达式 - */ - private AlarmStrategyExpressionDTO strategyExpression; - - /** - * 告警策略过滤条件 - */ - private Map strategyFilterMap; - - /** - * 告警策略Action方式 - */ - private Map strategyActionMap; - - /** - * 修改时间 - */ - private Long gmtModify; - - 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; - } - - public Integer getDuration() { - return duration; - } - - public void setDuration(Integer duration) { - this.duration = duration; - } - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public AlarmStrategyExpressionDTO getStrategyExpression() { - return strategyExpression; - } - - public void setStrategyExpression(AlarmStrategyExpressionDTO strategyExpression) { - this.strategyExpression = strategyExpression; - } - - public Map getStrategyFilterMap() { - return strategyFilterMap; - } - - public void setStrategyFilterMap(Map strategyFilterMap) { - this.strategyFilterMap = strategyFilterMap; - } - - public Map getStrategyActionMap() { - return strategyActionMap; - } - - public void setStrategyActionMap(Map strategyActionMap) { - this.strategyActionMap = strategyActionMap; - } - - public Long getGmtModify() { - return gmtModify; - } - - public void setGmtModify(Long gmtModify) { - this.gmtModify = gmtModify; - } - - @Override - public String toString() { - return "AlarmRuleDTO{" + - "id=" + id + - ", name='" + name + '\'' + - ", duration=" + duration + - ", clusterId=" + clusterId + - ", strategyExpression=" + strategyExpression + - ", strategyFilterMap=" + strategyFilterMap + - ", strategyActionMap=" + strategyActionMap + - ", gmtModify=" + gmtModify + - '}'; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyActionDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyActionDTO.java deleted file mode 100644 index c93f18d9..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyActionDTO.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto.alarm; - -/** - * @author zengqiao - * @date 19/12/16 - */ -public class AlarmStrategyActionDTO { - private String actionWay; // 告知方式: kafka - - private String actionTag; - - public String getActionWay() { - return actionWay; - } - - public void setActionWay(String actionWay) { - this.actionWay = actionWay; - } - - public String getActionTag() { - return actionTag; - } - - public void setActionTag(String actionTag) { - this.actionTag = actionTag; - } - - @Override - public String toString() { - return "AlarmStrategyActionDTO{" + - "actionWay='" + actionWay + '\'' + - ", actionTag='" + actionTag + '\'' + - '}'; - } - - public boolean legal() { - if (actionWay == null - || actionTag == null) { - return false; - } - return true; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyExpressionDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyExpressionDTO.java deleted file mode 100644 index ca8a030c..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyExpressionDTO.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto.alarm; - -/** - * 策略表达式 - * @author zengqiao - * @date 19/12/16 - */ -public class AlarmStrategyExpressionDTO { - private String metric; - - private String opt; - - private Long threshold; - - private Integer duration; - - public String getMetric() { - return metric; - } - - public void setMetric(String metric) { - this.metric = metric; - } - - public String getOpt() { - return opt; - } - - public void setOpt(String opt) { - this.opt = opt; - } - - public Long getThreshold() { - return threshold; - } - - public void setThreshold(Long threshold) { - this.threshold = threshold; - } - - public Integer getDuration() { - return duration; - } - - public void setDuration(Integer duration) { - this.duration = duration; - } - - @Override - public String toString() { - return "AlarmStrategyExpressionModel{" + - "metric='" + metric + '\'' + - ", opt='" + opt + '\'' + - ", threshold=" + threshold + - ", duration=" + duration + - '}'; - } - - public boolean legal() { - if (metric == null - || opt == null - || threshold == null - || duration == null || duration <= 0) { - return false; - } - return true; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyFilterDTO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyFilterDTO.java deleted file mode 100644 index e5996a5c..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/alarm/AlarmStrategyFilterDTO.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto.alarm; - -/** - * 告警过滤条件 - * @author zengqiao - * @date 19/12/16 - */ -public class AlarmStrategyFilterDTO { - private String key; - - private String value; - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public String toString() { - return "AlarmStrategyFilterModel{" + - "key='" + key + '\'' + - ", value='" + value + '\'' + - '}'; - } - - public boolean legal() { - if (key == null - || value == null) { - return false; - } - return true; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BaseMetrics.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BaseMetrics.java deleted file mode 100644 index e4fc0910..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BaseMetrics.java +++ /dev/null @@ -1,394 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.metrics; - -import com.xiaojukeji.kafka.manager.common.constant.MetricsType; -import com.xiaojukeji.kafka.manager.common.entity.annotations.FieldSelector; -import com.xiaojukeji.kafka.manager.common.entity.po.BaseEntryDO; - -/** - * @author zengqiao - * @date 19/11/25 - */ -public class BaseMetrics extends BaseEntryDO { - /** - * 每秒流入的近一分钟的均值、平均字节数、近五分钟均值、近十五分钟均值 - */ - @FieldSelector(types = { - MetricsType.BROKER_FLOW_DETAIL, - MetricsType.BROKER_TO_DB_METRICS, - MetricsType.BROKER_REAL_TIME_METRICS, - MetricsType.BROKER_OVER_VIEW_METRICS, - MetricsType.BROKER_ANALYSIS_METRICS, - MetricsType.BROKER_TOPIC_ANALYSIS_METRICS, - MetricsType.TOPIC_FLOW_DETAIL, - MetricsType.TOPIC_FLOW_OVERVIEW, - MetricsType.TOPIC_METRICS_TO_DB - }) - protected Double bytesInPerSec = 0.0; - protected Double bytesInPerSecMeanRate = 0.0; - protected Double bytesInPerSecFiveMinuteRate = 0.0; - protected Double bytesInPerSecFifteenMinuteRate = 0.0; - - /** - * 每秒流出的近一分钟的均值、平均字节数、近五分钟均值、近十五分钟均值 - */ - @FieldSelector(types = { - MetricsType.BROKER_FLOW_DETAIL, - MetricsType.BROKER_TO_DB_METRICS, - MetricsType.BROKER_REAL_TIME_METRICS, - MetricsType.BROKER_OVER_VIEW_METRICS, - MetricsType.BROKER_ANALYSIS_METRICS, - MetricsType.BROKER_TOPIC_ANALYSIS_METRICS, - MetricsType.TOPIC_FLOW_DETAIL, - MetricsType.TOPIC_METRICS_TO_DB - }) - protected Double bytesOutPerSec = 0.0; - protected Double bytesOutPerSecMeanRate = 0.0; - protected Double bytesOutPerSecFiveMinuteRate = 0.0; - protected Double bytesOutPerSecFifteenMinuteRate = 0.0; - - /** - * 每秒流入的近一分钟的均值、平均字节数、近五分钟均值、近十五分钟均值 - */ - @FieldSelector(types = { - MetricsType.BROKER_FLOW_DETAIL, - MetricsType.BROKER_TO_DB_METRICS, - MetricsType.BROKER_REAL_TIME_METRICS, - MetricsType.BROKER_ANALYSIS_METRICS, - MetricsType.BROKER_TOPIC_ANALYSIS_METRICS, - MetricsType.TOPIC_FLOW_DETAIL, - MetricsType.TOPIC_METRICS_TO_DB - }) - protected Double messagesInPerSec = 0.0; - protected Double messagesInPerSecMeanRate = 0.0; - protected Double messagesInPerSecFiveMinuteRate = 0.0; - protected Double messagesInPerSecFifteenMinuteRate = 0.0; - - /** - * 每秒拒绝的近一分钟的均值、平均字节数、近五分钟均值、近十五分钟均值 - */ - @FieldSelector(types = { - MetricsType.BROKER_FLOW_DETAIL, - MetricsType.BROKER_TO_DB_METRICS, - MetricsType.BROKER_REAL_TIME_METRICS, - MetricsType.TOPIC_FLOW_DETAIL, - MetricsType.TOPIC_METRICS_TO_DB - }) - protected Double bytesRejectedPerSec = 0.0; - protected Double bytesRejectedPerSecMeanRate = 0.0; - protected Double bytesRejectedPerSecFiveMinuteRate = 0.0; - protected Double bytesRejectedPerSecFifteenMinuteRate = 0.0; - - /** - * 每秒失败的Produce请求数的近一分钟的均值、平均字节数、近五分钟均值、近十五分钟均值 - */ - @FieldSelector(types = { - MetricsType.BROKER_FLOW_DETAIL, - MetricsType.BROKER_TO_DB_METRICS, - MetricsType.BROKER_REAL_TIME_METRICS, - MetricsType.TOPIC_FLOW_DETAIL - }) - protected Double failProduceRequestPerSec = 0.0; - protected Double failProduceRequestPerSecMeanRate = 0.0; - protected Double failProduceRequestPerSecFiveMinuteRate = 0.0; - protected Double failProduceRequestPerSecFifteenMinuteRate = 0.0; - - /** - * 每秒失败的Fetch请求数的近一分钟的均值、平均字节数、近五分钟均值、近十五分钟均值 - */ - @FieldSelector(types = { - MetricsType.BROKER_FLOW_DETAIL, - MetricsType.BROKER_TO_DB_METRICS, - MetricsType.BROKER_REAL_TIME_METRICS, - MetricsType.TOPIC_FLOW_DETAIL - }) - protected Double failFetchRequestPerSec = 0.0; - protected Double failFetchRequestPerSecMeanRate = 0.0; - protected Double failFetchRequestPerSecFiveMinuteRate = 0.0; - protected Double failFetchRequestPerSecFifteenMinuteRate = 0.0; - - /** - * 每秒总Produce请求数的近一分钟的均值、平均字节数、近五分钟均值、近十五分钟均值 - */ - @FieldSelector(types = { - MetricsType.BROKER_FLOW_DETAIL, - MetricsType.BROKER_ANALYSIS_METRICS, - MetricsType.BROKER_TOPIC_ANALYSIS_METRICS, - MetricsType.TOPIC_FLOW_DETAIL, - MetricsType.TOPIC_METRICS_TO_DB, - MetricsType.TOPIC_FLOW_OVERVIEW - }) - protected Double totalProduceRequestsPerSec = 0.0; - protected Double totalProduceRequestsPerSecMeanRate = 0.0; - protected Double totalProduceRequestsPerSecFiveMinuteRate = 0.0; - protected Double totalProduceRequestsPerSecFifteenMinuteRate = 0.0; - - /** - * 每秒总Fetch请求数的近一分钟的均值、平均字节数、近五分钟均值、近十五分钟均值 - */ - @FieldSelector(types = { - MetricsType.BROKER_FLOW_DETAIL, - MetricsType.BROKER_ANALYSIS_METRICS, - MetricsType.BROKER_TOPIC_ANALYSIS_METRICS, - MetricsType.TOPIC_FLOW_DETAIL - }) - protected Double totalFetchRequestsPerSec = 0.0; - protected Double totalFetchRequestsPerSecMeanRate = 0.0; - protected Double totalFetchRequestsPerSecFiveMinuteRate = 0.0; - protected Double totalFetchRequestsPerSecFifteenMinuteRate = 0.0; - - public Double getBytesInPerSec() { - return bytesInPerSec; - } - - public void setBytesInPerSec(Double bytesInPerSec) { - this.bytesInPerSec = bytesInPerSec; - } - - public Double getBytesInPerSecMeanRate() { - return bytesInPerSecMeanRate; - } - - public void setBytesInPerSecMeanRate(Double bytesInPerSecMeanRate) { - this.bytesInPerSecMeanRate = bytesInPerSecMeanRate; - } - - public Double getBytesInPerSecFiveMinuteRate() { - return bytesInPerSecFiveMinuteRate; - } - - public void setBytesInPerSecFiveMinuteRate(Double bytesInPerSecFiveMinuteRate) { - this.bytesInPerSecFiveMinuteRate = bytesInPerSecFiveMinuteRate; - } - - public Double getBytesInPerSecFifteenMinuteRate() { - return bytesInPerSecFifteenMinuteRate; - } - - public void setBytesInPerSecFifteenMinuteRate(Double bytesInPerSecFifteenMinuteRate) { - this.bytesInPerSecFifteenMinuteRate = bytesInPerSecFifteenMinuteRate; - } - - public Double getBytesOutPerSec() { - return bytesOutPerSec; - } - - public void setBytesOutPerSec(Double bytesOutPerSec) { - this.bytesOutPerSec = bytesOutPerSec; - } - - public Double getBytesOutPerSecMeanRate() { - return bytesOutPerSecMeanRate; - } - - public void setBytesOutPerSecMeanRate(Double bytesOutPerSecMeanRate) { - this.bytesOutPerSecMeanRate = bytesOutPerSecMeanRate; - } - - public Double getBytesOutPerSecFiveMinuteRate() { - return bytesOutPerSecFiveMinuteRate; - } - - public void setBytesOutPerSecFiveMinuteRate(Double bytesOutPerSecFiveMinuteRate) { - this.bytesOutPerSecFiveMinuteRate = bytesOutPerSecFiveMinuteRate; - } - - public Double getBytesOutPerSecFifteenMinuteRate() { - return bytesOutPerSecFifteenMinuteRate; - } - - public void setBytesOutPerSecFifteenMinuteRate(Double bytesOutPerSecFifteenMinuteRate) { - this.bytesOutPerSecFifteenMinuteRate = bytesOutPerSecFifteenMinuteRate; - } - - public Double getMessagesInPerSec() { - return messagesInPerSec; - } - - public void setMessagesInPerSec(Double messagesInPerSec) { - this.messagesInPerSec = messagesInPerSec; - } - - public Double getMessagesInPerSecMeanRate() { - return messagesInPerSecMeanRate; - } - - public void setMessagesInPerSecMeanRate(Double messagesInPerSecMeanRate) { - this.messagesInPerSecMeanRate = messagesInPerSecMeanRate; - } - - public Double getMessagesInPerSecFiveMinuteRate() { - return messagesInPerSecFiveMinuteRate; - } - - public void setMessagesInPerSecFiveMinuteRate(Double messagesInPerSecFiveMinuteRate) { - this.messagesInPerSecFiveMinuteRate = messagesInPerSecFiveMinuteRate; - } - - public Double getMessagesInPerSecFifteenMinuteRate() { - return messagesInPerSecFifteenMinuteRate; - } - - public void setMessagesInPerSecFifteenMinuteRate(Double messagesInPerSecFifteenMinuteRate) { - this.messagesInPerSecFifteenMinuteRate = messagesInPerSecFifteenMinuteRate; - } - - public Double getBytesRejectedPerSec() { - return bytesRejectedPerSec; - } - - public void setBytesRejectedPerSec(Double bytesRejectedPerSec) { - this.bytesRejectedPerSec = bytesRejectedPerSec; - } - - public Double getBytesRejectedPerSecMeanRate() { - return bytesRejectedPerSecMeanRate; - } - - public void setBytesRejectedPerSecMeanRate(Double bytesRejectedPerSecMeanRate) { - this.bytesRejectedPerSecMeanRate = bytesRejectedPerSecMeanRate; - } - - public Double getBytesRejectedPerSecFiveMinuteRate() { - return bytesRejectedPerSecFiveMinuteRate; - } - - public void setBytesRejectedPerSecFiveMinuteRate(Double bytesRejectedPerSecFiveMinuteRate) { - this.bytesRejectedPerSecFiveMinuteRate = bytesRejectedPerSecFiveMinuteRate; - } - - public Double getBytesRejectedPerSecFifteenMinuteRate() { - return bytesRejectedPerSecFifteenMinuteRate; - } - - public void setBytesRejectedPerSecFifteenMinuteRate(Double bytesRejectedPerSecFifteenMinuteRate) { - this.bytesRejectedPerSecFifteenMinuteRate = bytesRejectedPerSecFifteenMinuteRate; - } - - public Double getFailProduceRequestPerSec() { - return failProduceRequestPerSec; - } - - public void setFailProduceRequestPerSec(Double failProduceRequestPerSec) { - this.failProduceRequestPerSec = failProduceRequestPerSec; - } - - public Double getFailProduceRequestPerSecMeanRate() { - return failProduceRequestPerSecMeanRate; - } - - public void setFailProduceRequestPerSecMeanRate(Double failProduceRequestPerSecMeanRate) { - this.failProduceRequestPerSecMeanRate = failProduceRequestPerSecMeanRate; - } - - public Double getFailProduceRequestPerSecFiveMinuteRate() { - return failProduceRequestPerSecFiveMinuteRate; - } - - public void setFailProduceRequestPerSecFiveMinuteRate(Double failProduceRequestPerSecFiveMinuteRate) { - this.failProduceRequestPerSecFiveMinuteRate = failProduceRequestPerSecFiveMinuteRate; - } - - public Double getFailProduceRequestPerSecFifteenMinuteRate() { - return failProduceRequestPerSecFifteenMinuteRate; - } - - public void setFailProduceRequestPerSecFifteenMinuteRate(Double failProduceRequestPerSecFifteenMinuteRate) { - this.failProduceRequestPerSecFifteenMinuteRate = failProduceRequestPerSecFifteenMinuteRate; - } - - public Double getFailFetchRequestPerSec() { - return failFetchRequestPerSec; - } - - public void setFailFetchRequestPerSec(Double failFetchRequestPerSec) { - this.failFetchRequestPerSec = failFetchRequestPerSec; - } - - public Double getFailFetchRequestPerSecMeanRate() { - return failFetchRequestPerSecMeanRate; - } - - public void setFailFetchRequestPerSecMeanRate(Double failFetchRequestPerSecMeanRate) { - this.failFetchRequestPerSecMeanRate = failFetchRequestPerSecMeanRate; - } - - public Double getFailFetchRequestPerSecFiveMinuteRate() { - return failFetchRequestPerSecFiveMinuteRate; - } - - public void setFailFetchRequestPerSecFiveMinuteRate(Double failFetchRequestPerSecFiveMinuteRate) { - this.failFetchRequestPerSecFiveMinuteRate = failFetchRequestPerSecFiveMinuteRate; - } - - public Double getFailFetchRequestPerSecFifteenMinuteRate() { - return failFetchRequestPerSecFifteenMinuteRate; - } - - public void setFailFetchRequestPerSecFifteenMinuteRate(Double failFetchRequestPerSecFifteenMinuteRate) { - this.failFetchRequestPerSecFifteenMinuteRate = failFetchRequestPerSecFifteenMinuteRate; - } - - public Double getTotalProduceRequestsPerSec() { - return totalProduceRequestsPerSec; - } - - public void setTotalProduceRequestsPerSec(Double totalProduceRequestsPerSec) { - this.totalProduceRequestsPerSec = totalProduceRequestsPerSec; - } - - public Double getTotalProduceRequestsPerSecMeanRate() { - return totalProduceRequestsPerSecMeanRate; - } - - public void setTotalProduceRequestsPerSecMeanRate(Double totalProduceRequestsPerSecMeanRate) { - this.totalProduceRequestsPerSecMeanRate = totalProduceRequestsPerSecMeanRate; - } - - public Double getTotalProduceRequestsPerSecFiveMinuteRate() { - return totalProduceRequestsPerSecFiveMinuteRate; - } - - public void setTotalProduceRequestsPerSecFiveMinuteRate(Double totalProduceRequestsPerSecFiveMinuteRate) { - this.totalProduceRequestsPerSecFiveMinuteRate = totalProduceRequestsPerSecFiveMinuteRate; - } - - public Double getTotalProduceRequestsPerSecFifteenMinuteRate() { - return totalProduceRequestsPerSecFifteenMinuteRate; - } - - public void setTotalProduceRequestsPerSecFifteenMinuteRate(Double totalProduceRequestsPerSecFifteenMinuteRate) { - this.totalProduceRequestsPerSecFifteenMinuteRate = totalProduceRequestsPerSecFifteenMinuteRate; - } - - public Double getTotalFetchRequestsPerSec() { - return totalFetchRequestsPerSec; - } - - public void setTotalFetchRequestsPerSec(Double totalFetchRequestsPerSec) { - this.totalFetchRequestsPerSec = totalFetchRequestsPerSec; - } - - public Double getTotalFetchRequestsPerSecMeanRate() { - return totalFetchRequestsPerSecMeanRate; - } - - public void setTotalFetchRequestsPerSecMeanRate(Double totalFetchRequestsPerSecMeanRate) { - this.totalFetchRequestsPerSecMeanRate = totalFetchRequestsPerSecMeanRate; - } - - public Double getTotalFetchRequestsPerSecFiveMinuteRate() { - return totalFetchRequestsPerSecFiveMinuteRate; - } - - public void setTotalFetchRequestsPerSecFiveMinuteRate(Double totalFetchRequestsPerSecFiveMinuteRate) { - this.totalFetchRequestsPerSecFiveMinuteRate = totalFetchRequestsPerSecFiveMinuteRate; - } - - public Double getTotalFetchRequestsPerSecFifteenMinuteRate() { - return totalFetchRequestsPerSecFifteenMinuteRate; - } - - public void setTotalFetchRequestsPerSecFifteenMinuteRate(Double totalFetchRequestsPerSecFifteenMinuteRate) { - this.totalFetchRequestsPerSecFifteenMinuteRate = totalFetchRequestsPerSecFifteenMinuteRate; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BrokerMetrics.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BrokerMetrics.java deleted file mode 100644 index ff7aa04a..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BrokerMetrics.java +++ /dev/null @@ -1,331 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.metrics; - -import com.xiaojukeji.kafka.manager.common.constant.Constant; -import com.xiaojukeji.kafka.manager.common.constant.MetricsType; -import com.xiaojukeji.kafka.manager.common.entity.annotations.FieldSelector; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; - -/** - * 需要定时拉取的broker数据 - * @author tukun - * @date 2015/11/6. - */ -public class BrokerMetrics extends BaseMetrics { - /** - * 集群ID - */ - private Long clusterId; - - /** - * Topic名称 - */ - private Integer brokerId; - - /** - * 每秒Produce请求数的近一分钟的均值、平均字节数、近五分钟均值、近十五分钟均值 - */ - @FieldSelector(types = { - MetricsType.BROKER_FLOW_DETAIL, - MetricsType.BROKER_TO_DB_METRICS, - MetricsType.BROKER_REAL_TIME_METRICS - }) - private Double produceRequestPerSec = 0.0; - private Double produceRequestPerSecMeanRate = 0.0; - private Double produceRequestPerSecFiveMinuteRate = 0.0; - private Double produceRequestPerSecFifteenMinuteRate = 0.0; - - /** - * 每秒Fetch请求数的近一分钟的均值、平均字节数、近五分钟均值、近十五分钟均值 - */ - @FieldSelector(types = { - MetricsType.BROKER_FLOW_DETAIL, - MetricsType.BROKER_TO_DB_METRICS, - MetricsType.BROKER_REAL_TIME_METRICS - }) - private Double fetchConsumerRequestPerSec = 0.0; - private Double fetchConsumerRequestPerSecMeanRate = 0.0; - private Double fetchConsumerRequestPerSecFiveMinuteRate = 0.0; - private Double fetchConsumerRequestPerSecFifteenMinuteRate = 0.0; - - /** - * Broker分区数量 - */ - @FieldSelector(types = {MetricsType.BROKER_OVER_ALL_METRICS, 5}) - private int partitionCount; - - /** - * Broker已同步分区数量 - */ - @FieldSelector(types = {MetricsType.BROKER_OVER_ALL_METRICS}) - private int underReplicatedPartitions; - - /** - * Broker Leader的数量 - */ - @FieldSelector(types = {MetricsType.BROKER_OVER_ALL_METRICS, 5}) - private int leaderCount; - - /** - * Broker请求处理器空闲百分比 - */ - @FieldSelector(types = {MetricsType.BROKER_TO_DB_METRICS}) - private Double requestHandlerAvgIdlePercent = 0.0; - - /** - * 网络处理器空闲百分比 - */ - @FieldSelector(types = {MetricsType.BROKER_TO_DB_METRICS}) - private Double networkProcessorAvgIdlePercent = 0.0; - - /** - * 请求列表大小 - */ - @FieldSelector(types = {MetricsType.BROKER_TO_DB_METRICS}) - private Integer requestQueueSize = 0; - - /** - * 响应列表大小 - */ - @FieldSelector(types = {MetricsType.BROKER_TO_DB_METRICS}) - private Integer responseQueueSize = 0; - - /** - * 刷日志时间 - */ - @FieldSelector(types = {MetricsType.BROKER_TO_DB_METRICS}) - private Double logFlushRateAndTimeMs = 0.0; - - /** - * produce请求总时间-平均值 - */ - @FieldSelector(types = {MetricsType.BROKER_TO_DB_METRICS}) - private Double totalTimeProduceMean = 0.0; - - /** - * produce请求总时间-99th - */ - @FieldSelector(types = {MetricsType.BROKER_TO_DB_METRICS}) - private Double totalTimeProduce99Th = 0.0; - - /** - * fetch consumer请求总时间-平均值 - */ - @FieldSelector(types = {MetricsType.BROKER_TO_DB_METRICS}) - private Double totalTimeFetchConsumerMean = 0.0; - - /** - * fetch consumer请求总时间-99th - */ - @FieldSelector(types = {MetricsType.BROKER_TO_DB_METRICS}) - private Double totalTimeFetchConsumer99Th = 0.0; - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public Integer getBrokerId() { - return brokerId; - } - - public void setBrokerId(Integer brokerId) { - this.brokerId = brokerId; - } - - public Double getProduceRequestPerSec() { - return produceRequestPerSec; - } - - public void setProduceRequestPerSec(Double produceRequestPerSec) { - this.produceRequestPerSec = produceRequestPerSec; - } - - public Double getProduceRequestPerSecMeanRate() { - return produceRequestPerSecMeanRate; - } - - public void setProduceRequestPerSecMeanRate(Double produceRequestPerSecMeanRate) { - this.produceRequestPerSecMeanRate = produceRequestPerSecMeanRate; - } - - public Double getProduceRequestPerSecFiveMinuteRate() { - return produceRequestPerSecFiveMinuteRate; - } - - public void setProduceRequestPerSecFiveMinuteRate(Double produceRequestPerSecFiveMinuteRate) { - this.produceRequestPerSecFiveMinuteRate = produceRequestPerSecFiveMinuteRate; - } - - public Double getProduceRequestPerSecFifteenMinuteRate() { - return produceRequestPerSecFifteenMinuteRate; - } - - public void setProduceRequestPerSecFifteenMinuteRate(Double produceRequestPerSecFifteenMinuteRate) { - this.produceRequestPerSecFifteenMinuteRate = produceRequestPerSecFifteenMinuteRate; - } - - public Double getFetchConsumerRequestPerSec() { - return fetchConsumerRequestPerSec; - } - - public void setFetchConsumerRequestPerSec(Double fetchConsumerRequestPerSec) { - this.fetchConsumerRequestPerSec = fetchConsumerRequestPerSec; - } - - public Double getFetchConsumerRequestPerSecMeanRate() { - return fetchConsumerRequestPerSecMeanRate; - } - - public void setFetchConsumerRequestPerSecMeanRate(Double fetchConsumerRequestPerSecMeanRate) { - this.fetchConsumerRequestPerSecMeanRate = fetchConsumerRequestPerSecMeanRate; - } - - public Double getFetchConsumerRequestPerSecFiveMinuteRate() { - return fetchConsumerRequestPerSecFiveMinuteRate; - } - - public void setFetchConsumerRequestPerSecFiveMinuteRate(Double fetchConsumerRequestPerSecFiveMinuteRate) { - this.fetchConsumerRequestPerSecFiveMinuteRate = fetchConsumerRequestPerSecFiveMinuteRate; - } - - public Double getFetchConsumerRequestPerSecFifteenMinuteRate() { - return fetchConsumerRequestPerSecFifteenMinuteRate; - } - - public void setFetchConsumerRequestPerSecFifteenMinuteRate(Double fetchConsumerRequestPerSecFifteenMinuteRate) { - this.fetchConsumerRequestPerSecFifteenMinuteRate = fetchConsumerRequestPerSecFifteenMinuteRate; - } - - public int getPartitionCount() { - return partitionCount; - } - - public void setPartitionCount(int partitionCount) { - this.partitionCount = partitionCount; - } - - public int getUnderReplicatedPartitions() { - return underReplicatedPartitions; - } - - public void setUnderReplicatedPartitions(int underReplicatedPartitions) { - this.underReplicatedPartitions = underReplicatedPartitions; - } - - public int getLeaderCount() { - return leaderCount; - } - - public void setLeaderCount(int leaderCount) { - this.leaderCount = leaderCount; - } - - public Double getRequestHandlerAvgIdlePercent() { - return requestHandlerAvgIdlePercent; - } - - public void setRequestHandlerAvgIdlePercent(Double requestHandlerAvgIdlePercent) { - this.requestHandlerAvgIdlePercent = requestHandlerAvgIdlePercent; - } - - public Double getNetworkProcessorAvgIdlePercent() { - return networkProcessorAvgIdlePercent; - } - - public void setNetworkProcessorAvgIdlePercent(Double networkProcessorAvgIdlePercent) { - this.networkProcessorAvgIdlePercent = networkProcessorAvgIdlePercent; - } - - public Integer getRequestQueueSize() { - return requestQueueSize; - } - - public void setRequestQueueSize(Integer requestQueueSize) { - this.requestQueueSize = requestQueueSize; - } - - public Integer getResponseQueueSize() { - return responseQueueSize; - } - - public void setResponseQueueSize(Integer responseQueueSize) { - this.responseQueueSize = responseQueueSize; - } - - public Double getLogFlushRateAndTimeMs() { - return logFlushRateAndTimeMs; - } - - public void setLogFlushRateAndTimeMs(Double logFlushRateAndTimeMs) { - this.logFlushRateAndTimeMs = logFlushRateAndTimeMs; - } - - public Double getTotalTimeProduceMean() { - return totalTimeProduceMean; - } - - public void setTotalTimeProduceMean(Double totalTimeProduceMean) { - this.totalTimeProduceMean = totalTimeProduceMean; - } - - public Double getTotalTimeProduce99Th() { - return totalTimeProduce99Th; - } - - public void setTotalTimeProduce99Th(Double totalTimeProduce99Th) { - this.totalTimeProduce99Th = totalTimeProduce99Th; - } - - public Double getTotalTimeFetchConsumerMean() { - return totalTimeFetchConsumerMean; - } - - public void setTotalTimeFetchConsumerMean(Double totalTimeFetchConsumerMean) { - this.totalTimeFetchConsumerMean = totalTimeFetchConsumerMean; - } - - public Double getTotalTimeFetchConsumer99Th() { - return totalTimeFetchConsumer99Th; - } - - public void setTotalTimeFetchConsumer99Th(Double totalTimeFetchConsumer99Th) { - this.totalTimeFetchConsumer99Th = totalTimeFetchConsumer99Th; - } - - private static void initialization(Field[] fields){ - for(Field field : fields){ - FieldSelector annotation = field.getAnnotation(FieldSelector.class); - if(annotation ==null){ - continue; - } - - String fieldName; - if("".equals(annotation.name())) { - fieldName = field.getName().substring(0,1).toUpperCase() + field.getName().substring(1); - } else{ - fieldName = annotation.name(); - } - for(int type: annotation.types()){ - List list = Constant.BROKER_METRICS_TYPE_MBEAN_NAME_MAP.getOrDefault(type, new ArrayList<>()); - list.add(fieldName); - Constant.BROKER_METRICS_TYPE_MBEAN_NAME_MAP.put(type, list); - } - } - } - - public static List getFieldNameList(int metricsType){ - synchronized (BrokerMetrics.class) { - if (Constant.BROKER_METRICS_TYPE_MBEAN_NAME_MAP.isEmpty()) { - initialization(BrokerMetrics.class.getDeclaredFields()); - initialization(BaseMetrics.class.getDeclaredFields()); - } - } - return Constant.BROKER_METRICS_TYPE_MBEAN_NAME_MAP.getOrDefault(metricsType, new ArrayList<>()); - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicMetrics.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicMetrics.java deleted file mode 100644 index 1c09c2ff..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicMetrics.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.metrics; - -import com.xiaojukeji.kafka.manager.common.constant.Constant; -import com.xiaojukeji.kafka.manager.common.entity.annotations.FieldSelector; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; - -public class TopicMetrics extends BaseMetrics { - /** - * 集群ID - */ - private Long clusterId; - - /** - * Topic名称 - */ - private String topicName; - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - private static void initialization(Field[] fields){ - for(Field field : fields){ - FieldSelector annotation = field.getAnnotation(FieldSelector.class); - if(annotation ==null){ - continue; - } - String fieldName; - if("".equals(annotation.name())){ - String name = field.getName(); - fieldName = name.substring(0,1).toUpperCase()+name.substring(1); - }else{ - fieldName = annotation.name(); - } - for(int type: annotation.types()){ - List list = Constant.TOPIC_METRICS_TYPE_MBEAN_NAME_MAP.getOrDefault(type, new ArrayList<>()); - list.add(fieldName); - Constant.TOPIC_METRICS_TYPE_MBEAN_NAME_MAP.put(type, list); - } - } - } - - public static List getFieldNameList(int type){ - synchronized (TopicMetrics.class) { - if (Constant.TOPIC_METRICS_TYPE_MBEAN_NAME_MAP.isEmpty()) { - initialization(TopicMetrics.class.getDeclaredFields()); - initialization(BaseMetrics.class.getDeclaredFields()); - } - } - return Constant.TOPIC_METRICS_TYPE_MBEAN_NAME_MAP.get(type); - } - -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/AlarmRuleDO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/AlarmRuleDO.java deleted file mode 100644 index 7fdeb1ef..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/AlarmRuleDO.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; - -public class AlarmRuleDO extends BaseDO { - private String alarmName; - - private String strategyExpressions; - - private String strategyFilters; - - private String strategyActions; - - private String principals; - - public String getAlarmName() { - return alarmName; - } - - public void setAlarmName(String alarmName) { - this.alarmName = alarmName; - } - - public String getStrategyExpressions() { - return strategyExpressions; - } - - public void setStrategyExpressions(String strategyExpressions) { - this.strategyExpressions = strategyExpressions; - } - - public String getStrategyFilters() { - return strategyFilters; - } - - public void setStrategyFilters(String strategyFilters) { - this.strategyFilters = strategyFilters; - } - - public String getStrategyActions() { - return strategyActions; - } - - public void setStrategyActions(String strategyActions) { - this.strategyActions = strategyActions; - } - - public String getPrincipals() { - return principals; - } - - public void setPrincipals(String principals) { - this.principals = principals; - } - - @Override - public String toString() { - return "AlarmRuleDO{" + - "alarmName='" + alarmName + '\'' + - ", strategyExpressions='" + strategyExpressions + '\'' + - ", strategyFilters='" + strategyFilters + '\'' + - ", strategyActions='" + strategyActions + '\'' + - ", principals='" + principals + '\'' + - ", id=" + id + - ", status=" + status + - ", gmtCreate=" + gmtCreate + - ", gmtModify=" + gmtModify + - '}'; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BaseDO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BaseDO.java deleted file mode 100644 index 4d56dcbc..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BaseDO.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; - -import java.util.Date; - -/** - * @author arthur - * @date 2017/7/25. - */ -public class BaseDO { - protected Long id; - - protected Integer status; - - protected Date gmtCreate; - - protected Date gmtModify; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Integer getStatus() { - return status; - } - - public void setStatus(Integer status) { - this.status = status; - } - - public Date getGmtCreate() { - return gmtCreate; - } - - public void setGmtCreate(Date gmtCreate) { - this.gmtCreate = gmtCreate; - } - - public Date getGmtModify() { - return gmtModify; - } - - public void setGmtModify(Date gmtModify) { - this.gmtModify = gmtModify; - } - - @Override - public String toString() { - return "BaseDO{" + - "id=" + id + - ", status=" + status + - ", gmtCreate=" + gmtCreate + - ", gmtModify=" + gmtModify + - '}'; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BaseEntryDO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BaseEntryDO.java deleted file mode 100644 index 7cc6bcc4..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BaseEntryDO.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; - -import java.util.Date; - -/** - * @author zengqiao - * @date 19/11/25 - */ -public abstract class BaseEntryDO { - protected Long id; - - protected Date gmtCreate; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Date getGmtCreate() { - return gmtCreate; - } - - public void setGmtCreate(Date gmtCreate) { - this.gmtCreate = gmtCreate; - } - - @Override - public String toString() { - return "BaseEntryDO{" + - "id=" + id + - ", gmtCreate=" + gmtCreate + - '}'; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/ClusterMetricsDO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/ClusterMetricsDO.java deleted file mode 100644 index c7891ac3..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/ClusterMetricsDO.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; - -import com.xiaojukeji.kafka.manager.common.entity.metrics.BrokerMetrics; - -public class ClusterMetricsDO extends BaseEntryDO { - private Long clusterId; - - private Integer topicNum = 0; - - private Integer partitionNum = 0; - - private Integer brokerNum = 0; - - private Double bytesInPerSec = 0.0; - - private Double bytesOutPerSec = 0.0; - - private Double bytesRejectedPerSec = 0.0; - - private Double messagesInPerSec = 0.0; - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public Integer getTopicNum() { - return topicNum; - } - - public void setTopicNum(Integer topicNum) { - this.topicNum = topicNum; - } - - public Integer getPartitionNum() { - return partitionNum; - } - - public void setPartitionNum(Integer partitionNum) { - this.partitionNum = partitionNum; - } - - public Integer getBrokerNum() { - return brokerNum; - } - - public void setBrokerNum(Integer brokerNum) { - this.brokerNum = brokerNum; - } - - public Double getBytesInPerSec() { - return bytesInPerSec; - } - - public void setBytesInPerSec(Double bytesInPerSec) { - this.bytesInPerSec = bytesInPerSec; - } - - public Double getBytesOutPerSec() { - return bytesOutPerSec; - } - - public void setBytesOutPerSec(Double bytesOutPerSec) { - this.bytesOutPerSec = bytesOutPerSec; - } - - public Double getBytesRejectedPerSec() { - return bytesRejectedPerSec; - } - - public void setBytesRejectedPerSec(Double bytesRejectedPerSec) { - this.bytesRejectedPerSec = bytesRejectedPerSec; - } - - public Double getMessagesInPerSec() { - return messagesInPerSec; - } - - public void setMessagesInPerSec(Double messagesInPerSec) { - this.messagesInPerSec = messagesInPerSec; - } - - public void addBrokerMetrics(BrokerMetrics brokerMetrics) { - this.clusterId = brokerMetrics.getClusterId(); - this.brokerNum += 1; - this.bytesInPerSec += brokerMetrics.getBytesInPerSec(); - this.bytesOutPerSec += brokerMetrics.getBytesOutPerSec(); - this.bytesRejectedPerSec += brokerMetrics.getBytesRejectedPerSec(); - this.messagesInPerSec += brokerMetrics.getMessagesInPerSec(); - } - - @Override - public String toString() { - return "ClusterMetricsDO{" + - "clusterId=" + clusterId + - ", topicNum=" + topicNum + - ", partitionNum=" + partitionNum + - ", brokerNum=" + brokerNum + - ", bytesInPerSec=" + bytesInPerSec + - ", bytesOutPerSec=" + bytesOutPerSec + - ", bytesRejectedPerSec=" + bytesRejectedPerSec + - ", messagesInPerSec=" + messagesInPerSec + - ", id=" + id + - ", gmtCreate=" + gmtCreate + - '}'; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/MigrationTaskDO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/MigrationTaskDO.java deleted file mode 100644 index 218bf9f6..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/MigrationTaskDO.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; - -/** - * migrate topic task do - * @author zengqiao - * @date 19/4/16 - */ -public class MigrationTaskDO extends BaseDO { - private Long clusterId; - - private String topicName; - - private String reassignmentJson; - - private Long throttle; - - private String operator; - - private String description; - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getOperator() { - return operator; - } - - public void setOperator(String operator) { - this.operator = operator; - } - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - public String getReassignmentJson() { - return reassignmentJson; - } - - public void setReassignmentJson(String reassignmentJson) { - this.reassignmentJson = reassignmentJson; - } - - public Long getThrottle() { - return throttle; - } - - public void setThrottle(Long throttle) { - this.throttle = throttle; - } - - @Override - public String toString() { - return "MigrationTaskDO{" + - "clusterId=" + clusterId + - ", topicName='" + topicName + '\'' + - ", reassignmentJson='" + reassignmentJson + '\'' + - ", throttle=" + throttle + - ", id=" + id + - ", status=" + status + - ", gmtCreate=" + gmtCreate + - ", gmtModify=" + gmtModify + - '}'; - } - - public static MigrationTaskDO createInstance(Long clusterId, - String topicName, - String reassignmentJson, - Long throttle, - String description) { - MigrationTaskDO migrationTaskDO = new MigrationTaskDO(); - migrationTaskDO.setClusterId(clusterId); - migrationTaskDO.setTopicName(topicName); - migrationTaskDO.setReassignmentJson(reassignmentJson); - migrationTaskDO.setThrottle(throttle); - migrationTaskDO.setDescription(description); - return migrationTaskDO; - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OrderPartitionDO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OrderPartitionDO.java deleted file mode 100644 index 01666b18..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OrderPartitionDO.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; - -public class OrderPartitionDO extends BaseDO{ - private Long clusterId; - - private String clusterName; - - private String topicName; - - private String applicant; - - private Integer partitionNum; - - private String brokerList; - - private Long peakBytesIn; - - private String description; - - private Integer orderStatus; - - private String approver; - - private String opinion; - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public String getClusterName() { - return clusterName; - } - - public void setClusterName(String clusterName) { - this.clusterName = clusterName; - } - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - public String getApplicant() { - return applicant; - } - - public void setApplicant(String applicant) { - this.applicant = applicant; - } - - public Integer getPartitionNum() { - return partitionNum; - } - - public void setPartitionNum(Integer partitionNum) { - this.partitionNum = partitionNum; - } - - public String getBrokerList() { - return brokerList; - } - - public void setBrokerList(String brokerList) { - this.brokerList = brokerList; - } - - public Long getPeakBytesIn() { - return peakBytesIn; - } - - public void setPeakBytesIn(Long peakBytesIn) { - this.peakBytesIn = peakBytesIn; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public Integer getOrderStatus() { - return orderStatus; - } - - public void setOrderStatus(Integer orderStatus) { - this.orderStatus = orderStatus; - } - - public String getApprover() { - return approver; - } - - public void setApprover(String approver) { - this.approver = approver; - } - - public String getOpinion() { - return opinion; - } - - public void setOpinion(String opinion) { - this.opinion = opinion; - } - - @Override - public String toString() { - return "OrderPartitionDO{" + - "clusterId=" + clusterId + - ", clusterName='" + clusterName + '\'' + - ", topicName='" + topicName + '\'' + - ", applicant='" + applicant + '\'' + - ", partitionNum=" + partitionNum + - ", brokerList='" + brokerList + '\'' + - ", peakBytesIn=" + peakBytesIn + - ", description='" + description + '\'' + - ", orderStatus=" + orderStatus + - ", approver='" + approver + '\'' + - ", opinion='" + opinion + '\'' + - ", id=" + id + - ", status=" + status + - ", gmtCreate=" + gmtCreate + - ", gmtModify=" + gmtModify + - '}'; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OrderTopicDO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OrderTopicDO.java deleted file mode 100644 index ae376323..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OrderTopicDO.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; - -public class OrderTopicDO extends BaseDO { - private Long clusterId; - - private String clusterName; - - private String topicName; - - private Long retentionTime; - - private Integer partitionNum; - - private Integer replicaNum; - - private String regions; - - private String brokers; - - private Long peakBytesIn; - - private String applicant; - - private String principals; - - private String description; - - private Integer orderStatus; - - private String approver; - - private String opinion; - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public String getClusterName() { - return clusterName; - } - - public void setClusterName(String clusterName) { - this.clusterName = clusterName; - } - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - public Long getRetentionTime() { - return retentionTime; - } - - public void setRetentionTime(Long retentionTime) { - this.retentionTime = retentionTime; - } - - public Integer getPartitionNum() { - return partitionNum; - } - - public void setPartitionNum(Integer partitionNum) { - this.partitionNum = partitionNum; - } - - public Integer getReplicaNum() { - return replicaNum; - } - - public void setReplicaNum(Integer replicaNum) { - this.replicaNum = replicaNum; - } - - public String getRegions() { - return regions; - } - - public void setRegions(String regions) { - this.regions = regions; - } - - public String getBrokers() { - return brokers; - } - - public void setBrokers(String brokers) { - this.brokers = brokers; - } - - public Long getPeakBytesIn() { - return peakBytesIn; - } - - public void setPeakBytesIn(Long peakBytesIn) { - this.peakBytesIn = peakBytesIn; - } - - public String getApplicant() { - return applicant; - } - - public void setApplicant(String applicant) { - this.applicant = applicant; - } - - public String getPrincipals() { - return principals; - } - - public void setPrincipals(String principals) { - this.principals = principals; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public Integer getOrderStatus() { - return orderStatus; - } - - public void setOrderStatus(Integer orderStatus) { - this.orderStatus = orderStatus; - } - - public String getApprover() { - return approver; - } - - public void setApprover(String approver) { - this.approver = approver; - } - - public String getOpinion() { - return opinion; - } - - public void setOpinion(String opinion) { - this.opinion = opinion; - } - - @Override - public String toString() { - return "OrderTopicDO{" + - "clusterId=" + clusterId + - ", clusterName='" + clusterName + '\'' + - ", topicName='" + topicName + '\'' + - ", retentionTime=" + retentionTime + - ", partitionNum=" + partitionNum + - ", replicaNum=" + replicaNum + - ", regions='" + regions + '\'' + - ", brokers='" + brokers + '\'' + - ", peakBytesIn=" + peakBytesIn + - ", applicant='" + applicant + '\'' + - ", principals='" + principals + '\'' + - ", description='" + description + '\'' + - ", orderStatus=" + orderStatus + - ", approver='" + approver + '\'' + - ", opinion='" + opinion + '\'' + - ", id=" + id + - ", status=" + status + - ", gmtCreate=" + gmtCreate + - ", gmtModify=" + gmtModify + - '}'; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/RegionDO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/RegionDO.java deleted file mode 100644 index 306114cc..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/RegionDO.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; - -public class RegionDO extends BaseDO{ - private String regionName; - - private Long clusterId; - - private String brokerList; - - private Integer level; - - private String description; - - private String operator; - - public String getRegionName() { - return regionName; - } - - public void setRegionName(String regionName) { - this.regionName = regionName; - } - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public String getBrokerList() { - return brokerList; - } - - public void setBrokerList(String brokerList) { - this.brokerList = brokerList; - } - - public Integer getLevel() { - return level; - } - - public void setLevel(Integer level) { - this.level = level; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getOperator() { - return operator; - } - - public void setOperator(String operator) { - this.operator = operator; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/TopicDO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/TopicDO.java deleted file mode 100644 index e85fe98c..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/TopicDO.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; - -public class TopicDO extends BaseDO{ - private Long clusterId; - - private String topicName; - - private String applicant; - - private String principals; - - private String description; - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - public String getApplicant() { - return applicant; - } - - public void setApplicant(String applicant) { - this.applicant = applicant; - } - - public String getPrincipals() { - return principals; - } - - public void setPrincipals(String principals) { - this.principals = principals; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public String toString() { - return "TopicDO{" + - "clusterId=" + clusterId + - ", topicName='" + topicName + '\'' + - ", applicant='" + applicant + '\'' + - ", principals='" + principals + '\'' + - ", description='" + description + '\'' + - ", id=" + id + - ", status=" + status + - ", gmtCreate=" + gmtCreate + - ", gmtModify=" + gmtModify + - '}'; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/TopicFavoriteDO.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/TopicFavoriteDO.java deleted file mode 100644 index 01683eda..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/TopicFavoriteDO.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; - -public class TopicFavoriteDO extends BaseDO{ - private String username; - - private Long clusterId; - - private String topicName; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - @Override - public String toString() { - return "TopicFavoriteDO{" + - "username='" + username + '\'' + - ", clusterId=" + clusterId + - ", topicName='" + topicName + '\'' + - ", id=" + id + - ", status=" + status + - ", gmtCreate=" + gmtCreate + - ", gmtModify=" + gmtModify + - '}'; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/AlarmRuleQueryOption.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/AlarmRuleQueryOption.java deleted file mode 100644 index 09447131..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/AlarmRuleQueryOption.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po.query; - -/** - * @author zengqiao - * @date 19/12/2 - */ -public class AlarmRuleQueryOption extends BaseQueryOption { - private String alarmName; - - public String getAlarmName() { - return alarmName; - } - - public void setAlarmName(String alarmName) { - this.alarmName = alarmName; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/BaseQueryOption.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/BaseQueryOption.java deleted file mode 100644 index 09d59f19..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/BaseQueryOption.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po.query; - -/** - * @author zengqiao - * @date 19/12/2 - */ -public class BaseQueryOption { - protected Long id; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - @Override - public String toString() { - return "BaseQueryOption{" + - "id=" + id + - '}'; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/ClusterQueryOption.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/ClusterQueryOption.java deleted file mode 100644 index 5bf8b181..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/query/ClusterQueryOption.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.entity.po.query; - -/** - * @author zengqiao - * @date 19/12/4 - */ -public class ClusterQueryOption extends BaseQueryOption { - private String clusterName; - - public String getClusterName() { - return clusterName; - } - - public void setClusterName(String clusterName) { - this.clusterName = clusterName; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DateUtils.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DateUtils.java deleted file mode 100644 index 64220db3..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DateUtils.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.utils; - -import java.util.Calendar; -import java.util.Date; - -/** - * 日期工具 - * @author huangyiminghappy@163.com - * @date 2019-03-20 - */ -public class DateUtils { - public static Date long2Date(Long time){ - return new Date(time); - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConnectorWrap.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConnectorWrap.java deleted file mode 100644 index 3199bc72..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConnectorWrap.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.utils.jmx; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; -import java.io.IOException; -import java.net.MalformedURLException; - -/** - * JMXConnector包装类 - * @author tukun - * @date 2015/11/9. - */ -public class JmxConnectorWrap { - private final static Logger logger = LoggerFactory.getLogger(JmxConnectorWrap.class); - - private JMXConnector jmxConnector; - - /** - * JMX连接的主机名 - */ - private String host; - - /** - * JMX连接端口 - */ - private int port; - - public JmxConnectorWrap(String host, int port) { - this.host = host; - this.port = port; - } - - public JMXConnector getJmxConnector() { - // 如果JMX连接断开,则进行重新连接 - if (jmxConnector == null && port != -1) { - createJMXConnector(); - } - return jmxConnector; - } - - private synchronized void createJMXConnector() { - if (jmxConnector != null) { - return; - } - - String jmxUrl = String.format("service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi", host, port); - try { - JMXServiceURL url = new JMXServiceURL(jmxUrl); - jmxConnector = JMXConnectorFactory.connect(url, null); - } catch (MalformedURLException e) { - logger.error("JMX url exception, host:{} port:{} jmxUrl:{}", host, port, jmxUrl, e); - } catch (IOException e) { - logger.error("JMX connect exception, host:{} port:{}.", host, port, e); - } - logger.info("JMX connect success, host:{} port:{}.", host, port); - } - - public void close() { - if (jmxConnector == null) { - return; - } - try { - jmxConnector.close(); - } catch (IOException e) { - logger.warn("close JmxConnector exception, host:{} port:{}.", host, port, e); - } - } -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtil.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtil.java deleted file mode 100644 index a62296b1..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtil.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.utils.jmx; - -import java.util.HashMap; -import java.util.Map; - -/** - * kafka集群的mbean的object name集合 - * @author tukun, zengqiao - * @date 2015/11/5. - */ -public class MbeanNameUtil { - - //broker监控参数 - private static final String MESSAGE_IN_PER_SEC = "kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec"; - private static final String BYTES_IN_PER_SEC = "kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec"; - private static final String BYTES_OUT_PER_SEC = "kafka.server:type=BrokerTopicMetrics,name=BytesOutPerSec"; - private static final String BYTES_REJECTED_PER_SEC = "kafka.server:type=BrokerTopicMetrics,name=BytesRejectedPerSec"; - private static final String FAILED_FETCH_REQUEST_PER_SEC = "kafka.server:type=BrokerTopicMetrics,name=FailedFetchRequestsPerSec"; - private static final String FAILED_PRODUCE_REQUEST_PER_SEC = "kafka.server:type=BrokerTopicMetrics,name=FailedProduceRequestsPerSec"; - private static final String PRODUCE_REQUEST_PER_SEC = "kafka.network:type=RequestMetrics,name=RequestsPerSec,request=Produce"; - private static final String CONSUMER_REQUEST_PER_SEC = "kafka.network:type=RequestMetrics,name=RequestsPerSec,request=FetchConsumer"; - private static final String TOTAL_PRODUCE_REQUEST_PER_SEC = "kafka.server:type=BrokerTopicMetrics,name=TotalProduceRequestsPerSec"; - private static final String TOTAL_FETCH_REQUEST_PER_SEC = "kafka.server:type=BrokerTopicMetrics,name=TotalFetchRequestsPerSec"; - - private static final String REQUEST_HANDLER_AVG_IDLE_PERCENT = "kafka.server:type=KafkaRequestHandlerPool,name=RequestHandlerAvgIdlePercent"; - private static final String NETWORK_PROCESSOR_AVG_IDLE_PERCENT = "kafka.network:type=SocketServer,name=NetworkProcessorAvgIdlePercent"; - private static final String REQUEST_QUEUE_SIZE = "kafka.network:type=RequestChannel,name=RequestQueueSize"; - private static final String RESPONSE_QUEUE_SIZE = "kafka.network:type=RequestChannel,name=ResponseQueueSize"; - private static final String LOG_FLUSH_RATE_AND_TIME_MS = "kafka.log:type=LogFlushStats,name=LogFlushRateAndTimeMs"; - private static final String TOTAL_TIME_PRODUCE = "kafka.network:type=RequestMetrics,name=TotalTimeMs,request=Produce"; - private static final String TOTAL_TIME_FETCH_CONSUMER = "kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchConsumer"; - - private static final String PART_COUNT = "kafka.server:type=ReplicaManager,name=PartitionCount"; - private static final String PARTITION_OFFSET_PULL = "kafka.log:type=Log,name=LogEndOffset,topic=${topic},partition=${partition}"; - private static final String UNDER_REPLICATED_PARTITIONS = "kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions"; - private static final String LEADER_COUNT = "kafka.server:type=ReplicaManager,name=LeaderCount"; - - -// private static final String PRODUCE_REQUEST_TIME = "kafka.network:type=TopicRequestMetrics,name=TotalTimeMs,request=Produce"; -// private static final String FETCH_REQUEST_TIME = "kafka.network:type=TopicRequestMetrics,name=TotalTimeMs,request=FetchConsumer"; - - - //存储监控的参数name到获取的object_name的映射关系图 - private static Map mbeanNameMap = new HashMap(); - static { - //监控参数配置,object_name和监控的属性名 - mbeanNameMap.put("MessagesInPerSec", new Mbean(MESSAGE_IN_PER_SEC,"OneMinuteRate", Double.class)); - mbeanNameMap.put("BytesInPerSec", new Mbean(BYTES_IN_PER_SEC,"OneMinuteRate", Double.class)); - mbeanNameMap.put("BytesOutPerSec", new Mbean(BYTES_OUT_PER_SEC,"OneMinuteRate", Double.class)); - mbeanNameMap.put("BytesRejectedPerSec", new Mbean(BYTES_REJECTED_PER_SEC,"OneMinuteRate", Double.class)); - mbeanNameMap.put("FailFetchRequestPerSec", new Mbean(FAILED_FETCH_REQUEST_PER_SEC,"OneMinuteRate", Double.class)); - mbeanNameMap.put("FailProduceRequestPerSec", new Mbean(FAILED_PRODUCE_REQUEST_PER_SEC,"OneMinuteRate", Double.class)); - mbeanNameMap.put("ProduceRequestPerSec", new Mbean(PRODUCE_REQUEST_PER_SEC,"OneMinuteRate", Double.class)); - mbeanNameMap.put("FetchConsumerRequestPerSec", new Mbean(CONSUMER_REQUEST_PER_SEC,"OneMinuteRate", Double.class)); - mbeanNameMap.put("TotalProduceRequestsPerSec", new Mbean(TOTAL_PRODUCE_REQUEST_PER_SEC,"OneMinuteRate", Double.class)); - mbeanNameMap.put("TotalFetchRequestsPerSec", new Mbean(TOTAL_FETCH_REQUEST_PER_SEC,"OneMinuteRate", Double.class)); - - - mbeanNameMap.put("PartitionOffset", new Mbean(PARTITION_OFFSET_PULL,"Value", int.class)); - - mbeanNameMap.put("PartitionCount", new Mbean(PART_COUNT,"Value", int.class)); - mbeanNameMap.put("UnderReplicatedPartitions", new Mbean(UNDER_REPLICATED_PARTITIONS,"Value", int.class)); - mbeanNameMap.put("LeaderCount", new Mbean(LEADER_COUNT,"Value", int.class)); - - mbeanNameMap.put("RequestHandlerAvgIdlePercent", new Mbean(REQUEST_HANDLER_AVG_IDLE_PERCENT,"OneMinuteRate", Double.class)); - mbeanNameMap.put("NetworkProcessorAvgIdlePercent", new Mbean(NETWORK_PROCESSOR_AVG_IDLE_PERCENT,"Value", Double.class)); - mbeanNameMap.put("RequestQueueSize", new Mbean(REQUEST_QUEUE_SIZE,"Value", int.class)); - mbeanNameMap.put("ResponseQueueSize", new Mbean(RESPONSE_QUEUE_SIZE, "Value", int.class)); - mbeanNameMap.put("LogFlushRateAndTimeMs", new Mbean(LOG_FLUSH_RATE_AND_TIME_MS,"OneMinuteRate", Double.class)); - mbeanNameMap.put("TotalTimeProduceMean", new Mbean(TOTAL_TIME_PRODUCE,"Mean", Double.class)); - mbeanNameMap.put("TotalTimeProduce99Th", new Mbean(TOTAL_TIME_PRODUCE,"99thPercentile", Double.class)); - mbeanNameMap.put("TotalTimeFetchConsumerMean", new Mbean(TOTAL_TIME_FETCH_CONSUMER,"Mean", Double.class)); - mbeanNameMap.put("TotalTimeFetchConsumer99Th", new Mbean(TOTAL_TIME_FETCH_CONSUMER,"99thPercentile", Double.class)); - -// mbeanNameMap.put("ProduceRequestTime", new Mbean(PRODUCE_REQUEST_TIME,"Value")); -// mbeanNameMap.put("FetchRequestTime", new Mbean(FETCH_REQUEST_TIME,"Value")); - } - - /** - * 根据属性名,kafka版本,topic获取相应的Mbean - */ - public static Mbean getMbean(String name, String topic) { - Mbean mbean = mbeanNameMap.get(name); - if (mbean == null) { - return null; - } - if (topic != null && !topic.isEmpty()) { - return new Mbean(mbean.getObjectName() + ",topic=" + topic, mbean.getProperty(), mbean.getPropertyClass()); - } - return mbean; - } - -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/StateChangeListener.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/StateChangeListener.java deleted file mode 100644 index 62866d6e..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/StateChangeListener.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.utils.zk; - -/** - * Created by limeng on 2017/12/22 - */ -public interface StateChangeListener { - - enum State { - CONNECTION_RECONNECT, // - CONNECTION_DISCONNECT, NODE_DATA_CHANGED, CHILD_UPDATED, CHILD_ADDED, CHILD_DELETED, - // - ; - } - - void onChange(State state, String path); - -} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/ZkPathUtil.java b/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/ZkPathUtil.java deleted file mode 100644 index 97af6ce7..00000000 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/ZkPathUtil.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.xiaojukeji.kafka.manager.common.utils.zk; - -import java.util.HashMap; -import java.util.Map; - -/** - * 存储结构: - * - *
- * /consumers
- *    consumer-group
- *      ids
- *        consumerId
- *      offsets
- *        topic-0
- *           0(partition编号,节点内容表示)
- *           1
- *           2
- *        topic-1
- *      owners
- * /brokers
- *     topics
- *          topic-0  (节点内容是 ("0",[0,1,2]))
- *              partitions
- *                  0
- *                      state(节点内容是leader的brokerId,同步副本信息等)
- *                  1
- *                  2
- *          topic-x
- *     ids
- *          1(临时节点,broker编号,节点信息为broker相关信息,如JMX端口,host和port等)
- *          2
- *          n
- * 
- * - * @author tukun @ 2015-11-5 - * @version 1.0.0 - */ -public class ZkPathUtil { - - public static final String ZOOKEEPER_SEPARATOR = "/"; - - public static final String BROKER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "brokers"; - - public static final String CONTROLLER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "controller"; - - public static final String BROKER_IDS_ROOT = BROKER_ROOT_NODE - + ZOOKEEPER_SEPARATOR + "ids"; - - public static final String BROKER_TOPICS_ROOT = BROKER_ROOT_NODE - + ZOOKEEPER_SEPARATOR + "topics"; - - public static final String CONSUMER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "consumers"; - - public static final String CONFIG_ROOT_NODE = ZOOKEEPER_SEPARATOR + "config"; - - public static final String CONFIG_TOPICS_ROOT_NODE = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "topics"; - - //存储监控的参数name到获取的object_name的映射关系图 - private static Map zkPathMap = new HashMap(); - - static { - zkPathMap.put("ConusmerPartitionOffset", CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR - + "${consumerGroup}" + ZOOKEEPER_SEPARATOR - + "offsets" + ZOOKEEPER_SEPARATOR + "${topic}" - + ZOOKEEPER_SEPARATOR + "${partition}"); - } - - //for broker目录 - public static String getBrokerIdNodePath(long brokerId) { - return String.format(BROKER_IDS_ROOT + ZOOKEEPER_SEPARATOR + "%d", brokerId); - } - - public static String getBrokerTopicRoot(String topic) { - return BROKER_TOPICS_ROOT + ZOOKEEPER_SEPARATOR + topic; - } - - public static String getBrokerTopicPartitionRoot(String topic) { - return BROKER_TOPICS_ROOT + ZOOKEEPER_SEPARATOR + topic + ZOOKEEPER_SEPARATOR - + "partitions"; - } - - public static String getBrokerTopicPartitionStatePath(String topic, int partitionId) { - return String.format(getBrokerTopicPartitionRoot(topic) + ZOOKEEPER_SEPARATOR + "%d" - + ZOOKEEPER_SEPARATOR + "state", partitionId); - } - - //for consumer - public static String getConsumerTopicPartitionOffsetNodePath(String consumerGroup, - String topic, int partitionId) { - return String.format(CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR + "%s" + ZOOKEEPER_SEPARATOR - + "offset" + "%s" + "%d", consumerGroup, topic, partitionId); - } - - public static String getConsumerGroupRoot(String consumerGroup) { - return CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR + consumerGroup; - } - - public static String getConsumerGroupIdsRoot(String consumerGroup) { - return CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR + consumerGroup + ZOOKEEPER_SEPARATOR - + "ids"; - } - - public static String getConsumerGroupOffsetRoot(String consumerGroup) { - return CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR + consumerGroup + ZOOKEEPER_SEPARATOR - + "offsets"; - } - - public static String getConsumerGroupOwnersRoot(String consumerGroup) { - return CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR + consumerGroup + ZOOKEEPER_SEPARATOR - + "owners"; - } - - public static String getConsumerGroupConsumerIdsNodePath(String consumerGroup, String consumerId) { - return getConsumerGroupIdsRoot(consumerGroup) + ZOOKEEPER_SEPARATOR + consumerId; - } - - public static String getConsumerGroupOffsetTopicNode(String consumerGroup, String topic) { - return getConsumerGroupOffsetRoot(consumerGroup) + ZOOKEEPER_SEPARATOR + topic; - } - - public static String getConsumerGroupOffsetTopicPartitionNode(String consumerGroup, - String topic, int partitionId) { - return getConsumerGroupOffsetTopicNode(consumerGroup, topic) + ZOOKEEPER_SEPARATOR - + partitionId; - } - - public static String getConsumerGroupOwnersTopicNode(String consumerGroup, String topic) { - return getConsumerGroupOwnersRoot(consumerGroup) + ZOOKEEPER_SEPARATOR + topic; - } - - public static String getConsumerGroupOwnersTopicPartitionNode(String consumerGroup, - String topic, int partitionId) { - return getConsumerGroupOwnersTopicNode(consumerGroup, topic) + ZOOKEEPER_SEPARATOR - + partitionId; - } - - public static String getConfigTopicNode(String topicName) { - return CONFIG_TOPICS_ROOT_NODE + ZOOKEEPER_SEPARATOR + topicName; - } - - public static String parseLastPartFromZkPath(String zkPath) { - return zkPath.substring(zkPath.lastIndexOf("/") + 1); - } - - public static Map getZkPathMap() { - return zkPathMap; - } - - public static void setZkPathMap(Map zkPathMap) { - ZkPathUtil.zkPathMap = zkPathMap; - } - - public static String getControllerRootNode() { - return CONTROLLER_ROOT_NODE; - } - - public static String getEntityConfigPath(String entityType, String entity) { - return getEntityConfigRootPath(entityType) + "/" + entity; - } - - public static String getEntityConfigRootPath(String entityType) { - return CONFIG_ROOT_NODE + "/" + entityType; - } -} diff --git a/console/package-lock.json b/console/package-lock.json deleted file mode 100644 index 5b64b1b2..00000000 --- a/console/package-lock.json +++ /dev/null @@ -1,9510 +0,0 @@ -{ - "name": "mobx-ts-example", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@ant-design/icons": { - "version": "1.2.1", - "resolved": "http://registry.npm.taobao.org/@ant-design/icons/download/@ant-design/icons-1.2.1.tgz", - "integrity": "sha1-jhkwGxQz7GfWu9DoknguKt5WH/k=", - "dev": true - }, - "@ant-design/icons-react": { - "version": "1.1.5", - "resolved": "http://registry.npm.taobao.org/@ant-design/icons-react/download/@ant-design/icons-react-1.1.5.tgz", - "integrity": "sha1-GwPajcztKku5gu97JcHSQBTDWmg=", - "dev": true, - "requires": { - "ant-design-palettes": "^1.1.3", - "babel-runtime": "^6.26.0" - } - }, - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "http://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.0.0.tgz", - "integrity": "sha1-BuKrGb21NThVWaq7W6WXKUgoAPg=", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/highlight": { - "version": "7.0.0", - "resolved": "http://registry.npm.taobao.org/@babel/highlight/download/@babel/highlight-7.0.0.tgz", - "integrity": "sha1-9xDDjI1Fjm3ZogGvtjf8t4HOmeQ=", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/runtime": { - "version": "7.4.3", - "resolved": "http://registry.npm.taobao.org/@babel/runtime/download/@babel/runtime-7.4.3.tgz", - "integrity": "sha1-eYiORSA0IjrZYJGHoK0f4NKtS9w=", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.2" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.2", - "resolved": "http://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.13.2.tgz", - "integrity": "sha1-MuWcmm+5saSv8JtJMMotRHc0NEc=", - "dev": true - } - } - }, - "@hot-loader/react-dom": { - "version": "16.8.6", - "resolved": "http://registry.npm.taobao.org/@hot-loader/react-dom/download/@hot-loader/react-dom-16.8.6.tgz", - "integrity": "sha1-eSO6J9sVY6fMSNTgsoeaFA30Yeo=", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.6" - } - }, - "@types/anymatch": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/@types/anymatch/download/@types/anymatch-1.3.1.tgz?cache=0&sync_timestamp=1580841236934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fanymatch%2Fdownload%2F%40types%2Fanymatch-1.3.1.tgz", - "integrity": "sha1-M2utwb7sudrMOL6izzKt9ieoQho=", - "dev": true - }, - "@types/echarts": { - "version": "4.1.9", - "resolved": "https://registry.npm.taobao.org/@types/echarts/download/@types/echarts-4.1.9.tgz", - "integrity": "sha1-hv33yoKYeVNc87GxSQ4vRqDqCTM=", - "dev": true, - "requires": { - "@types/zrender": "*" - } - }, - "@types/events": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/@types/events/download/@types/events-3.0.0.tgz?cache=0&sync_timestamp=1580841806837&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fevents%2Fdownload%2F%40types%2Fevents-3.0.0.tgz", - "integrity": "sha1-KGLz9Yqaf3w+eNefEw3U1xwlwqc=", - "dev": true - }, - "@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npm.taobao.org/@types/glob/download/@types/glob-7.1.1.tgz", - "integrity": "sha1-qlmhxuP7xCHgfM0xqUTDDrpSFXU=", - "dev": true, - "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/history": { - "version": "4.7.2", - "resolved": "http://registry.npm.taobao.org/@types/history/download/@types/history-4.7.2.tgz", - "integrity": "sha1-DmcOolTVWSQbbus4lPh1SZHnMiA=", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "http://registry.npm.taobao.org/@types/json5/download/@types/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/@types/minimatch/download/@types/minimatch-3.0.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fminimatch%2Fdownload%2F%40types%2Fminimatch-3.0.3.tgz", - "integrity": "sha1-PcoOPzOyAPx9ETnAzZbBJoyt/Z0=", - "dev": true - }, - "@types/node": { - "version": "13.9.8", - "resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-13.9.8.tgz", - "integrity": "sha1-CZdkIPyAp6AL9AaAxjgV7Yx2FvQ=", - "dev": true - }, - "@types/prop-types": { - "version": "15.7.1", - "resolved": "http://registry.npm.taobao.org/@types/prop-types/download/@types/prop-types-15.7.1.tgz", - "integrity": "sha1-8aEee6uww8rWgQC+OB0eBkxo8fY=", - "dev": true - }, - "@types/q": { - "version": "1.5.2", - "resolved": "http://registry.npm.taobao.org/@types/q/download/@types/q-1.5.2.tgz", - "integrity": "sha1-aQoUdbhPKohP0HzXl8APXzE1bqg=", - "dev": true - }, - "@types/react": { - "version": "16.8.13", - "resolved": "http://registry.npm.taobao.org/@types/react/download/@types/react-16.8.13.tgz", - "integrity": "sha1-qCsVqtmrkcQO3KDWiJt3Ra4k8FM=", - "dev": true, - "requires": { - "@types/prop-types": "*", - "csstype": "^2.2.0" - } - }, - "@types/react-dom": { - "version": "16.8.4", - "resolved": "http://registry.npm.taobao.org/@types/react-dom/download/@types/react-dom-16.8.4.tgz", - "integrity": "sha1-f7e6NohXx6oPTkURxHEMosWhKog=", - "dev": true, - "requires": { - "@types/react": "*" - } - }, - "@types/react-router": { - "version": "4.4.5", - "resolved": "http://registry.npm.taobao.org/@types/react-router/download/@types/react-router-4.4.5.tgz", - "integrity": "sha1-EWaZfcfu8pF7XrzokOvssy7lwbM=", - "dev": true, - "requires": { - "@types/history": "*", - "@types/react": "*" - } - }, - "@types/react-router-dom": { - "version": "4.3.2", - "resolved": "http://registry.npm.taobao.org/@types/react-router-dom/download/@types/react-router-dom-4.3.2.tgz", - "integrity": "sha1-UsF8NoJZdjjzHBfEJiBAPcXCo/U=", - "dev": true, - "requires": { - "@types/history": "*", - "@types/react": "*", - "@types/react-router": "*" - } - }, - "@types/react-slick": { - "version": "0.23.3", - "resolved": "http://registry.npm.taobao.org/@types/react-slick/download/@types/react-slick-0.23.3.tgz", - "integrity": "sha1-ydFDI6dfVPRqZS+3Rf5VOq0JHOA=", - "dev": true, - "requires": { - "@types/react": "*" - } - }, - "@types/source-list-map": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/@types/source-list-map/download/@types/source-list-map-0.1.2.tgz", - "integrity": "sha1-AHiDYGP/rxdBI0m7o2QIfgrALsk=", - "dev": true - }, - "@types/tapable": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/@types/tapable/download/@types/tapable-1.0.5.tgz?cache=0&sync_timestamp=1580844951142&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Ftapable%2Fdownload%2F%40types%2Ftapable-1.0.5.tgz", - "integrity": "sha1-mtvBKVBYKqZerXa//fOf4MJ6PAI=", - "dev": true - }, - "@types/uglify-js": { - "version": "3.0.4", - "resolved": "https://registry.npm.taobao.org/@types/uglify-js/download/@types/uglify-js-3.0.4.tgz", - "integrity": "sha1-lr6uI99vVhhiqDC0KIpJ6GuqwII=", - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "@types/webpack": { - "version": "4.41.10", - "resolved": "https://registry.npm.taobao.org/@types/webpack/download/@types/webpack-4.41.10.tgz", - "integrity": "sha1-Lh9rNQiiSYVO/j3MdpCQWsXuEL4=", - "dev": true, - "requires": { - "@types/anymatch": "*", - "@types/node": "*", - "@types/tapable": "*", - "@types/uglify-js": "*", - "@types/webpack-sources": "*", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "@types/webpack-sources": { - "version": "0.1.7", - "resolved": "https://registry.npm.taobao.org/@types/webpack-sources/download/@types/webpack-sources-0.1.7.tgz?cache=0&sync_timestamp=1584978716401&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fwebpack-sources%2Fdownload%2F%40types%2Fwebpack-sources-0.1.7.tgz", - "integrity": "sha1-CjMKlFYRNBDHSl1kGArwy8oAcUE=", - "dev": true, - "requires": { - "@types/node": "*", - "@types/source-list-map": "*", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "@types/zrender": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/@types/zrender/download/@types/zrender-4.0.0.tgz", - "integrity": "sha1-poBvEuxOzKrr2bDYFvBJrKYYj70=", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/ast/download/@webassemblyjs/ast-1.8.5.tgz", - "integrity": "sha1-UbHF/mV2o0lTv0slPfnw1JDZ41k=", - "dev": true, - "requires": { - "@webassemblyjs/helper-module-context": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/wast-parser": "1.8.5" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/floating-point-hex-parser/download/@webassemblyjs/floating-point-hex-parser-1.8.5.tgz", - "integrity": "sha1-G6kmopI2E+3OSW/VsC6M6KX0lyE=", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-api-error/download/@webassemblyjs/helper-api-error-1.8.5.tgz", - "integrity": "sha1-xJ2tIvZFInxe22EL25aX8aq3Ifc=", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-buffer/download/@webassemblyjs/helper-buffer-1.8.5.tgz", - "integrity": "sha1-/qk+Qphj3V5DOFVfQikjhaZT8gQ=", - "dev": true - }, - "@webassemblyjs/helper-code-frame": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-code-frame/download/@webassemblyjs/helper-code-frame-1.8.5.tgz", - "integrity": "sha1-mnQP9I4/qjAisd/1RCPfmqKTwl4=", - "dev": true, - "requires": { - "@webassemblyjs/wast-printer": "1.8.5" - } - }, - "@webassemblyjs/helper-fsm": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-fsm/download/@webassemblyjs/helper-fsm-1.8.5.tgz", - "integrity": "sha1-ugt9Oz9+RzPaYFnJMyJ12GBwJFI=", - "dev": true - }, - "@webassemblyjs/helper-module-context": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-module-context/download/@webassemblyjs/helper-module-context-1.8.5.tgz", - "integrity": "sha1-3vS5knsBAdyMu9jR7bW3ucguskU=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "mamacro": "^0.0.3" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-wasm-bytecode/download/@webassemblyjs/helper-wasm-bytecode-1.8.5.tgz", - "integrity": "sha1-U3p1Dt31weky83RCBlUckcG5PmE=", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/helper-wasm-section/download/@webassemblyjs/helper-wasm-section-1.8.5.tgz", - "integrity": "sha1-dMpqa8vhnlCjtrRihH5pUD5r/L8=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/ieee754/download/@webassemblyjs/ieee754-1.8.5.tgz", - "integrity": "sha1-cSMp2+8kDza/V70ve4+5v0FUQh4=", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/leb128/download/@webassemblyjs/leb128-1.8.5.tgz", - "integrity": "sha1-BE7es06mefPgTNT9mCTV41dnrhA=", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/utf8/download/@webassemblyjs/utf8-1.8.5.tgz", - "integrity": "sha1-qL87XY/+mGx8Hjc8y9wqCRXwztw=", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wasm-edit/download/@webassemblyjs/wasm-edit-1.8.5.tgz", - "integrity": "sha1-li2hKqWswcExyBxCMpkcgs5W4Bo=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/helper-wasm-section": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5", - "@webassemblyjs/wasm-opt": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5", - "@webassemblyjs/wast-printer": "1.8.5" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wasm-gen/download/@webassemblyjs/wasm-gen-1.8.5.tgz", - "integrity": "sha1-VIQHZsLBAC62TtGr5yCt7XFPmLw=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/ieee754": "1.8.5", - "@webassemblyjs/leb128": "1.8.5", - "@webassemblyjs/utf8": "1.8.5" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wasm-opt/download/@webassemblyjs/wasm-opt-1.8.5.tgz", - "integrity": "sha1-sk2fa6UDlK8TSfUQr6j/y4pj0mQ=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wasm-parser/download/@webassemblyjs/wasm-parser-1.8.5.tgz", - "integrity": "sha1-IVdvDsiLkUJzV7hTY4NmjvfGa40=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-api-error": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/ieee754": "1.8.5", - "@webassemblyjs/leb128": "1.8.5", - "@webassemblyjs/utf8": "1.8.5" - } - }, - "@webassemblyjs/wast-parser": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wast-parser/download/@webassemblyjs/wast-parser-1.8.5.tgz", - "integrity": "sha1-4Q7s1ULQ5705T2gnxJ899tTu+4w=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/floating-point-hex-parser": "1.8.5", - "@webassemblyjs/helper-api-error": "1.8.5", - "@webassemblyjs/helper-code-frame": "1.8.5", - "@webassemblyjs/helper-fsm": "1.8.5", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/@webassemblyjs/wast-printer/download/@webassemblyjs/wast-printer-1.8.5.tgz", - "integrity": "sha1-EUu8SB/RDKDiOzVg+oEnSLC65bw=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/wast-parser": "1.8.5", - "@xtuc/long": "4.2.2" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/@xtuc/ieee754/download/@xtuc/ieee754-1.2.0.tgz", - "integrity": "sha1-7vAUoxRa5Hehy8AM0eVSM23Ot5A=", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "http://registry.npm.taobao.org/@xtuc/long/download/@xtuc/long-4.2.2.tgz", - "integrity": "sha1-0pHGpOl5ibXGHZrPOWrk/hM6cY0=", - "dev": true - }, - "accepts": { - "version": "1.3.5", - "resolved": "http://registry.npm.taobao.org/accepts/download/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", - "dev": true, - "requires": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" - } - }, - "acorn": { - "version": "6.1.1", - "resolved": "http://registry.npm.taobao.org/acorn/download/acorn-6.1.1.tgz", - "integrity": "sha1-fSWuBbuK0fm2mRCOEJTs14hK3B8=", - "dev": true - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/acorn-dynamic-import/download/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha1-SCIQFAWCo2uDw+NC4c/ryqkkCUg=", - "dev": true - }, - "add-dom-event-listener": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/add-dom-event-listener/download/add-dom-event-listener-1.1.0.tgz", - "integrity": "sha1-apLbOg3Qq8JU4JXA8dwUrLuq4xA=", - "dev": true, - "requires": { - "object-assign": "4.x" - } - }, - "ajv": { - "version": "6.10.0", - "resolved": "http://registry.npm.taobao.org/ajv/download/ajv-6.10.0.tgz", - "integrity": "sha1-kNDVRDnaWHzX6EO/twRfUL0ivfE=", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-errors": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/ajv-errors/download/ajv-errors-1.0.1.tgz", - "integrity": "sha1-81mGrOuRr63sQQL72FAUlQzvpk0=", - "dev": true - }, - "ajv-keywords": { - "version": "3.4.0", - "resolved": "http://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.4.0.tgz", - "integrity": "sha1-S4Mee1MUFafMUYzUBOc/YZPGNJ0=", - "dev": true - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/alphanum-sort/download/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "ansi-colors": { - "version": "3.2.4", - "resolved": "http://registry.npm.taobao.org/ansi-colors/download/ansi-colors-3.2.4.tgz", - "integrity": "sha1-46PaS/uubIapwoViXeEkojQCb78=", - "dev": true - }, - "ansi-html": { - "version": "0.0.7", - "resolved": "http://registry.npm.taobao.org/ansi-html/download/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "http://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "ant-design-palettes": { - "version": "1.1.3", - "resolved": "http://registry.npm.taobao.org/ant-design-palettes/download/ant-design-palettes-1.1.3.tgz", - "integrity": "sha1-hBGbGk2GNjrcUqONWH5lM2oKJ90=", - "dev": true, - "requires": { - "tinycolor2": "^1.4.1" - } - }, - "antd": { - "version": "3.16.3", - "resolved": "http://registry.npm.taobao.org/antd/download/antd-3.16.3.tgz", - "integrity": "sha1-Zuzb2Wox4qTSORBqEGsXYpvqoUE=", - "dev": true, - "requires": { - "@ant-design/icons": "~1.2.0", - "@ant-design/icons-react": "~1.1.5", - "@types/react-slick": "^0.23.3", - "array-tree-filter": "^2.1.0", - "babel-runtime": "6.x", - "classnames": "~2.2.6", - "copy-to-clipboard": "^3.0.8", - "create-react-class": "^15.6.3", - "create-react-context": "0.2.2", - "css-animation": "^1.5.0", - "dom-closest": "^0.2.0", - "enquire.js": "^2.1.6", - "lodash": "^4.17.11", - "moment": "^2.24.0", - "omit.js": "^1.0.0", - "prop-types": "^15.6.2", - "raf": "^3.4.0", - "rc-animate": "^2.5.4", - "rc-calendar": "~9.12.1", - "rc-cascader": "~0.17.0", - "rc-checkbox": "~2.1.5", - "rc-collapse": "~1.11.1", - "rc-dialog": "~7.3.0", - "rc-drawer": "~1.7.6", - "rc-dropdown": "~2.4.1", - "rc-editor-mention": "^1.1.7", - "rc-form": "^2.4.0", - "rc-input-number": "~4.4.0", - "rc-menu": "~7.4.12", - "rc-notification": "~3.3.0", - "rc-pagination": "~1.17.7", - "rc-progress": "~2.3.0", - "rc-rate": "~2.5.0", - "rc-select": "~9.0.0", - "rc-slider": "~8.6.5", - "rc-steps": "~3.3.0", - "rc-switch": "~1.9.0", - "rc-table": "~6.4.0", - "rc-tabs": "~9.6.0", - "rc-time-picker": "~3.6.1", - "rc-tooltip": "~3.7.3", - "rc-tree": "~1.15.2", - "rc-tree-select": "~2.6.0", - "rc-trigger": "^2.6.2", - "rc-upload": "~2.6.0", - "rc-util": "^4.5.1", - "react-lazy-load": "^3.0.13", - "react-lifecycles-compat": "^3.0.4", - "react-slick": "~0.23.2", - "resize-observer-polyfill": "^1.5.0", - "shallowequal": "^1.1.0", - "warning": "~4.0.2" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/anymatch/download/anymatch-2.0.0.tgz", - "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/normalize-path/download/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/aproba/download/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "http://registry.npm.taobao.org/argparse/download/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/arr-diff/download/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/arr-flatten/download/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/arr-union/download/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "http://registry.npm.taobao.org/array-flatten/download/array-flatten-2.1.2.tgz", - "integrity": "sha1-JO+AoowaiTYX4hSbDG0NeIKTsJk=", - "dev": true - }, - "array-tree-filter": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/array-tree-filter/download/array-tree-filter-2.1.0.tgz", - "integrity": "sha1-hzrAD+yDdJ8lWsjdCDgUtPYykZA=", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/array-union/download/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/array-uniq/download/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "http://registry.npm.taobao.org/array-unique/download/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asap": { - "version": "2.0.6", - "resolved": "http://registry.npm.taobao.org/asap/download/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "http://registry.npm.taobao.org/asn1/download/asn1-0.2.4.tgz", - "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", - "dev": true, - "optional": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "asn1.js": { - "version": "4.10.1", - "resolved": "http://registry.npm.taobao.org/asn1.js/download/asn1.js-4.10.1.tgz", - "integrity": "sha1-ucK/WAXx5kqt7tbfOiv6+1pz9aA=", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "assert": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/assert/download/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", - "dev": true, - "requires": { - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/inherits/download/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - }, - "util": { - "version": "0.10.3", - "resolved": "http://registry.npm.taobao.org/util/download/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - } - } - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/assign-symbols/download/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "async": { - "version": "1.5.2", - "resolved": "http://registry.npm.taobao.org/async/download/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "async-each": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/async-each/download/async-each-1.0.3.tgz", - "integrity": "sha1-tyfb+H12UWAvBvTUrDh/R9kbDL8=", - "dev": true - }, - "async-validator": { - "version": "1.8.5", - "resolved": "http://registry.npm.taobao.org/async-validator/download/async-validator-1.8.5.tgz", - "integrity": "sha1-3D4I7B/Q3dtn5ghC8CwM0c7G1/A=", - "dev": true, - "requires": { - "babel-runtime": "6.x" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "http://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true, - "optional": true - }, - "atob": { - "version": "2.1.2", - "resolved": "http://registry.npm.taobao.org/atob/download/atob-2.1.2.tgz", - "integrity": "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k=", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "http://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.8.0", - "resolved": "http://registry.npm.taobao.org/aws4/download/aws4-1.8.0.tgz", - "integrity": "sha1-8OAD2cqef1nHpQiUXXsu+aBKVC8=", - "dev": true, - "optional": true - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "http://registry.npm.taobao.org/babel-runtime/download/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "http://registry.npm.taobao.org/base/download/base-0.11.2.tgz", - "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base64-js": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/base64-js/download/base64-js-1.3.0.tgz", - "integrity": "sha1-yrHmEY8FEJXli1KBrqjBzSK/wOM=", - "dev": true - }, - "batch": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/batch/download/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "big.js": { - "version": "5.2.2", - "resolved": "http://registry.npm.taobao.org/big.js/download/big.js-5.2.2.tgz", - "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=", - "dev": true - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "http://registry.npm.taobao.org/binary-extensions/download/binary-extensions-1.13.1.tgz", - "integrity": "sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U=", - "dev": true - }, - "bluebird": { - "version": "3.5.4", - "resolved": "http://registry.npm.taobao.org/bluebird/download/bluebird-3.5.4.tgz", - "integrity": "sha1-1sxmFZXeMNWzr1/O3TwLPvbsVxQ=", - "dev": true - }, - "bn.js": { - "version": "4.11.8", - "resolved": "http://registry.npm.taobao.org/bn.js/download/bn.js-4.11.8.tgz", - "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=", - "dev": true - }, - "body-parser": { - "version": "1.18.3", - "resolved": "http://registry.npm.taobao.org/body-parser/download/body-parser-1.18.3.tgz", - "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", - "dev": true, - "requires": { - "bytes": "3.0.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "~1.6.3", - "iconv-lite": "0.4.23", - "on-finished": "~2.3.0", - "qs": "6.5.2", - "raw-body": "2.3.3", - "type-is": "~1.6.16" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "iconv-lite": { - "version": "0.4.23", - "resolved": "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.23.tgz", - "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "http://registry.npm.taobao.org/bonjour/download/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/boolbase/download/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "http://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "http://registry.npm.taobao.org/braces/download/braces-2.3.2.tgz", - "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/brorand/download/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/browserify-aes/download/browserify-aes-1.2.0.tgz", - "integrity": "sha1-Mmc0ZC9APavDADIJhTu3CtQo70g=", - "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/browserify-cipher/download/browserify-cipher-1.0.1.tgz", - "integrity": "sha1-jWR0wbhwv9q807z8wZNKEOlPFfA=", - "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/browserify-des/download/browserify-des-1.0.2.tgz", - "integrity": "sha1-OvTx9Zg5QDVy8cZiBDdfen9wPpw=", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/browserify-rsa/download/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "http://registry.npm.taobao.org/browserify-sign/download/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "dev": true, - "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "http://registry.npm.taobao.org/browserify-zlib/download/browserify-zlib-0.2.0.tgz", - "integrity": "sha1-KGlFnZqjviRf6P4sofRuLn9U1z8=", - "dev": true, - "requires": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "4.5.5", - "resolved": "http://registry.npm.taobao.org/browserslist/download/browserslist-4.5.5.tgz", - "integrity": "sha1-/ho1IzDSSQ1XNVdMFJqFvBjvm4I=", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30000960", - "electron-to-chromium": "^1.3.124", - "node-releases": "^1.1.14" - } - }, - "buffer": { - "version": "4.9.1", - "resolved": "http://registry.npm.taobao.org/buffer/download/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz", - "integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8=", - "dev": true - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/buffer-indexof/download/buffer-indexof-1.1.1.tgz", - "integrity": "sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow=", - "dev": true - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/buffer-xor/download/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/builtin-modules/download/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/builtin-status-codes/download/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, - "bytes": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true - }, - "cacache": { - "version": "11.3.2", - "resolved": "http://registry.npm.taobao.org/cacache/download/cacache-11.3.2.tgz", - "integrity": "sha1-LYHjCOPSWMo4Eltna5iyrJzmm/o=", - "dev": true, - "requires": { - "bluebird": "^3.5.3", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/cache-base/download/cache-base-1.0.1.tgz", - "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/caller-callsite/download/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/caller-path/download/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/callsites/download/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - }, - "camel-case": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/camel-case/download/camel-case-3.0.0.tgz", - "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", - "dev": true, - "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "http://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz", - "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", - "dev": true - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/caniuse-api/download/caniuse-api-3.0.0.tgz", - "integrity": "sha1-Xk2Q4idJYdRikZl99Znj7QCO5MA=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30000962", - "resolved": "http://registry.npm.taobao.org/caniuse-lite/download/caniuse-lite-1.0.30000962.tgz", - "integrity": "sha1-bBDDqzBLib6pBeZq35jAkFCI7kQ=", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "http://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true, - "optional": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "http://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz", - "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chokidar": { - "version": "2.1.5", - "resolved": "http://registry.npm.taobao.org/chokidar/download/chokidar-2.1.5.tgz", - "integrity": "sha1-CuhDTZYigaX1bHKGnnnLbZ2GrU0=", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "chownr": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/chownr/download/chownr-1.1.1.tgz", - "integrity": "sha1-VHJri4//TfBTxCGH6AH7RBLfFJQ=", - "dev": true - }, - "chrome-trace-event": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/chrome-trace-event/download/chrome-trace-event-1.0.0.tgz", - "integrity": "sha1-Rakb0sIMlBHwljtarrmhuV4JzEg=", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "http://registry.npm.taobao.org/cipher-base/download/cipher-base-1.0.4.tgz", - "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "http://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz", - "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "classnames": { - "version": "2.2.6", - "resolved": "http://registry.npm.taobao.org/classnames/download/classnames-2.2.6.tgz", - "integrity": "sha1-Q5Nb/90pHzJtrQogUwmzjQD2UM4=", - "dev": true - }, - "clean-css": { - "version": "4.2.1", - "resolved": "http://registry.npm.taobao.org/clean-css/download/clean-css-4.2.1.tgz", - "integrity": "sha1-LUEe92uFabbQyEBo2r6FsKpeXBc=", - "dev": true, - "requires": { - "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "clean-webpack-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/clean-webpack-plugin/download/clean-webpack-plugin-3.0.0.tgz", - "integrity": "sha1-qZ2Ow0wcYopFQVZ6p7RXRGRgxis=", - "dev": true, - "requires": { - "@types/webpack": "^4.4.31", - "del": "^4.1.1" - }, - "dependencies": { - "del": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/del/download/del-4.1.1.tgz", - "integrity": "sha1-no8RciLqRKMf86FWwEm5kFKp8LQ=", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - } - } - } - }, - "cliui": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/cliui/download/cliui-4.1.0.tgz", - "integrity": "sha1-NIQi2+gtgAswIu709qwQvy5NG0k=", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "clone": { - "version": "2.1.2", - "resolved": "http://registry.npm.taobao.org/clone/download/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true - }, - "coa": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/coa/download/coa-2.0.2.tgz", - "integrity": "sha1-Q/bCEVG07yv1cYfbDXPeIp4+fsM=", - "dev": true, - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/code-point-at/download/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/color/download/color-3.1.0.tgz", - "integrity": "sha1-2On7CWcyh1d0yEv5IoFd8DCND/w=", - "dev": true, - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "http://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz", - "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "http://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "color-string": { - "version": "1.5.3", - "resolved": "http://registry.npm.taobao.org/color-string/download/color-string-1.5.3.tgz", - "integrity": "sha1-ybvF8BtYtUkvPWhXRZy2WQziBMw=", - "dev": true, - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "combined-stream": { - "version": "1.0.7", - "resolved": "http://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.7.tgz", - "integrity": "sha1-LR0kMXr7ir6V1tLAsHtXgTU52Cg=", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.17.1", - "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.17.1.tgz", - "integrity": "sha1-vXerfebelCBc6sxy8XFtKfIKd78=", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/commondir/download/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "component-classes": { - "version": "1.2.6", - "resolved": "http://registry.npm.taobao.org/component-classes/download/component-classes-1.2.6.tgz", - "integrity": "sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE=", - "dev": true, - "requires": { - "component-indexof": "0.0.3" - } - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz", - "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=", - "dev": true - }, - "component-indexof": { - "version": "0.0.3", - "resolved": "http://registry.npm.taobao.org/component-indexof/download/component-indexof-0.0.3.tgz", - "integrity": "sha1-EdCRMSI5648yyPJa6csAL/6NPCQ=", - "dev": true - }, - "compressible": { - "version": "2.0.16", - "resolved": "http://registry.npm.taobao.org/compressible/download/compressible-2.0.16.tgz", - "integrity": "sha1-pJv5hY84IbZM4b4Clq/HOARmp38=", - "dev": true, - "requires": { - "mime-db": ">= 1.38.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "http://registry.npm.taobao.org/compression/download/compression-1.7.4.tgz", - "integrity": "sha1-lVI+/xcMpXwpoMpB5v4TH0Hlu48=", - "dev": true, - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "http://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "http://registry.npm.taobao.org/concat-stream/download/concat-stream-1.6.2.tgz", - "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "http://registry.npm.taobao.org/connect-history-api-fallback/download/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha1-izIIk1kwjRERFdgcrT/Oq4iPl7w=", - "dev": true - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/console-browserify/download/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "^0.1.4" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/constants-browserify/download/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "http://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true - }, - "content-type": { - "version": "1.0.4", - "resolved": "http://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", - "dev": true - }, - "cookie": { - "version": "0.3.1", - "resolved": "http://registry.npm.taobao.org/cookie/download/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "http://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "http://registry.npm.taobao.org/copy-concurrently/download/copy-concurrently-1.0.5.tgz", - "integrity": "sha1-kilzmMrjSTf8r9bsgTnBgFHwteA=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "http://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "copy-to-clipboard": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/copy-to-clipboard/download/copy-to-clipboard-3.1.0.tgz", - "integrity": "sha1-CigUGJnmvSF7ncE/0WibOziCC0Q=", - "dev": true, - "requires": { - "toggle-selection": "^1.0.6" - } - }, - "core-js": { - "version": "2.6.5", - "resolved": "http://registry.npm.taobao.org/core-js/download/core-js-2.6.5.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-2.6.5.tgz", - "integrity": "sha1-RLyNJJ5/sv9dAOA0Gn/7lPv2eJU=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cosmiconfig": { - "version": "5.2.0", - "resolved": "http://registry.npm.taobao.org/cosmiconfig/download/cosmiconfig-5.2.0.tgz", - "integrity": "sha1-RQOOTSin/nhyA67enCW8pKCLEsg=", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.0", - "parse-json": "^4.0.0" - } - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/create-ecdh/download/create-ecdh-4.0.3.tgz", - "integrity": "sha1-yREbbzMEXEaX8UR4f5JUzcd8Rf8=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/create-hash/download/create-hash-1.2.0.tgz", - "integrity": "sha1-iJB4rxGmN1a8+1m9IhmWvjqe8ZY=", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "http://registry.npm.taobao.org/create-hmac/download/create-hmac-1.1.7.tgz", - "integrity": "sha1-aRcMeLOrlXFHsriwRXLkfq0iQ/8=", - "dev": true, - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "create-react-class": { - "version": "15.6.3", - "resolved": "http://registry.npm.taobao.org/create-react-class/download/create-react-class-15.6.3.tgz", - "integrity": "sha1-LXMjf7P5cK5uvgEanmb0bbyoADY=", - "dev": true, - "requires": { - "fbjs": "^0.8.9", - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" - } - }, - "create-react-context": { - "version": "0.2.2", - "resolved": "http://registry.npm.taobao.org/create-react-context/download/create-react-context-0.2.2.tgz", - "integrity": "sha1-mDZUL5qqIoaM19Sm+CZn3zgBnco=", - "dev": true, - "requires": { - "fbjs": "^0.8.0", - "gud": "^1.0.0" - } - }, - "cross-env": { - "version": "7.0.2", - "resolved": "https://registry.npm.taobao.org/cross-env/download/cross-env-7.0.2.tgz?cache=0&sync_timestamp=1583443602692&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-env%2Fdownload%2Fcross-env-7.0.2.tgz", - "integrity": "sha1-vV7TEzmpOjQYrE88qco0Awgq5fk=", - "dev": true, - "requires": { - "cross-spawn": "^7.0.1" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.1", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-7.0.1.tgz", - "integrity": "sha1-CrVihuD3wk4VPQTMKqAn5DqaXRQ=", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-3.1.1.tgz", - "integrity": "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-2.0.0.tgz?cache=0&sync_timestamp=1567781622888&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshebang-command%2Fdownload%2Fshebang-command-2.0.0.tgz", - "integrity": "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-3.0.0.tgz", - "integrity": "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwhich%2Fdownload%2Fwhich-2.0.2.tgz", - "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "http://registry.npm.taobao.org/cross-spawn/download/cross-spawn-6.0.5.tgz", - "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "http://registry.npm.taobao.org/crypto-browserify/download/crypto-browserify-3.12.0.tgz", - "integrity": "sha1-OWz58xN/A+S45TLFj2mCVOAPgOw=", - "dev": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "css-animation": { - "version": "1.5.0", - "resolved": "http://registry.npm.taobao.org/css-animation/download/css-animation-1.5.0.tgz", - "integrity": "sha1-yWuQl6XvdKe+hIC0XMROTsbKK/U=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "component-classes": "^1.2.5" - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "http://registry.npm.taobao.org/css-color-names/download/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "dev": true - }, - "css-declaration-sorter": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/css-declaration-sorter/download/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha1-wZiUD2OnbX42wecQGLABchBUyyI=", - "dev": true, - "requires": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - } - }, - "css-loader": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/css-loader/download/css-loader-2.1.1.tgz", - "integrity": "sha1-2CVPcuQSuyI4u0TdZ0/770lzM+o=", - "dev": true, - "requires": { - "camelcase": "^5.2.0", - "icss-utils": "^4.1.0", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.14", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^2.0.6", - "postcss-modules-scope": "^2.1.0", - "postcss-modules-values": "^2.0.0", - "postcss-value-parser": "^3.3.0", - "schema-utils": "^1.0.0" - } - }, - "css-select": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/css-select/download/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "dev": true, - "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "http://registry.npm.taobao.org/css-select-base-adapter/download/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha1-Oy/0lyzDYquIVhUHqVQIoUMhNdc=", - "dev": true - }, - "css-tree": { - "version": "1.0.0-alpha.28", - "resolved": "http://registry.npm.taobao.org/css-tree/download/css-tree-1.0.0-alpha.28.tgz", - "integrity": "sha1-joloGQ2IbJR3vI1h6W9hrz9/+n8=", - "dev": true, - "requires": { - "mdn-data": "~1.1.0", - "source-map": "^0.5.3" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "css-unit-converter": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/css-unit-converter/download/css-unit-converter-1.1.1.tgz", - "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=", - "dev": true - }, - "css-url-regex": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/css-url-regex/download/css-url-regex-1.1.0.tgz", - "integrity": "sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w=", - "dev": true - }, - "css-what": { - "version": "2.1.3", - "resolved": "http://registry.npm.taobao.org/css-what/download/css-what-2.1.3.tgz", - "integrity": "sha1-ptdgRXM2X+dGhsPzEcVlE9iChfI=", - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/cssesc/download/cssesc-3.0.0.tgz", - "integrity": "sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4=", - "dev": true - }, - "cssnano": { - "version": "4.1.10", - "resolved": "http://registry.npm.taobao.org/cssnano/download/cssnano-4.1.10.tgz", - "integrity": "sha1-CsQfCxPRPUZUh+ERt3jULaYxuLI=", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.7", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "cssnano-preset-default": { - "version": "4.0.7", - "resolved": "http://registry.npm.taobao.org/cssnano-preset-default/download/cssnano-preset-default-4.0.7.tgz", - "integrity": "sha1-UexmLM/KD4izltzZZ5zbkxvhf3Y=", - "dev": true, - "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.2", - "postcss-unique-selectors": "^4.0.1" - } - }, - "cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/cssnano-util-get-arguments/download/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", - "dev": true - }, - "cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/cssnano-util-get-match/download/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", - "dev": true - }, - "cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/cssnano-util-raw-cache/download/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha1-sm1f1fcqEd/np4RvtMZyYPlr8oI=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/cssnano-util-same-parent/download/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha1-V0CC+yhZ0ttDOFWDXZqEVuoYu/M=", - "dev": true - }, - "csso": { - "version": "3.5.1", - "resolved": "http://registry.npm.taobao.org/csso/download/csso-3.5.1.tgz", - "integrity": "sha1-e564vmFiiXPBsmHhadLwJACOdYs=", - "dev": true, - "requires": { - "css-tree": "1.0.0-alpha.29" - }, - "dependencies": { - "css-tree": { - "version": "1.0.0-alpha.29", - "resolved": "http://registry.npm.taobao.org/css-tree/download/css-tree-1.0.0-alpha.29.tgz", - "integrity": "sha1-P6nU7zFCy9HDAedmTB81K9gvWjk=", - "dev": true, - "requires": { - "mdn-data": "~1.1.0", - "source-map": "^0.5.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "csstype": { - "version": "2.6.4", - "resolved": "http://registry.npm.taobao.org/csstype/download/csstype-2.6.4.tgz", - "integrity": "sha1-1YWmBiCW4yTnGH+A4E+SvQ8A438=", - "dev": true - }, - "cyclist": { - "version": "0.2.2", - "resolved": "http://registry.npm.taobao.org/cyclist/download/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", - "dev": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "http://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "date-now": { - "version": "0.1.4", - "resolved": "http://registry.npm.taobao.org/date-now/download/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, - "debug": { - "version": "4.1.1", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "http://registry.npm.taobao.org/decode-uri-component/download/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-equal": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/deep-equal/download/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", - "dev": true - }, - "deepmerge": { - "version": "2.2.1", - "resolved": "http://registry.npm.taobao.org/deepmerge/download/deepmerge-2.2.1.tgz", - "integrity": "sha1-XT/yKgHAD2RUBaL7wX0HeKGAEXA=", - "dev": true - }, - "default-gateway": { - "version": "4.2.0", - "resolved": "http://registry.npm.taobao.org/default-gateway/download/default-gateway-4.2.0.tgz", - "integrity": "sha1-FnEEx1AMIRX23WmwpTa7jtcgVSs=", - "dev": true, - "requires": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "http://registry.npm.taobao.org/define-properties/download/define-properties-1.1.3.tgz", - "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-2.0.2.tgz", - "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "del": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/del/download/del-4.1.0.tgz", - "integrity": "sha1-BJVDuCkOGpKT4r0VCrOgb2NzIrg=", - "dev": true, - "requires": { - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "depd": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "des.js": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/des.js/download/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "http://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "detect-file": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/detect-file/download/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, - "detect-node": { - "version": "2.0.4", - "resolved": "http://registry.npm.taobao.org/detect-node/download/detect-node-2.0.4.tgz", - "integrity": "sha1-AU7o+PZpxcWAI9pkuBecCDooxGw=", - "dev": true - }, - "diff": { - "version": "3.5.0", - "resolved": "http://registry.npm.taobao.org/diff/download/diff-3.5.0.tgz", - "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=", - "dev": true - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "http://registry.npm.taobao.org/diffie-hellman/download/diffie-hellman-5.0.3.tgz", - "integrity": "sha1-QOjumPVaIUlgcUaSHGPhrl89KHU=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/dns-equal/download/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "dns-packet": { - "version": "1.3.1", - "resolved": "http://registry.npm.taobao.org/dns-packet/download/dns-packet-1.3.1.tgz", - "integrity": "sha1-EqpCaYEHW+UAuRDu3NC0fdfe2lo=", - "dev": true, - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/dns-txt/download/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "dom-align": { - "version": "1.8.2", - "resolved": "http://registry.npm.taobao.org/dom-align/download/dom-align-1.8.2.tgz", - "integrity": "sha1-/c02vOJbqNNP41gu/Vesdn30kL0=", - "dev": true - }, - "dom-closest": { - "version": "0.2.0", - "resolved": "http://registry.npm.taobao.org/dom-closest/download/dom-closest-0.2.0.tgz", - "integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=", - "dev": true, - "requires": { - "dom-matches": ">=1.0.1" - } - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "http://registry.npm.taobao.org/dom-converter/download/dom-converter-0.2.0.tgz", - "integrity": "sha1-ZyGp2u4uKTaClVtq/kFncWJ7t2g=", - "dev": true, - "requires": { - "utila": "~0.4" - } - }, - "dom-matches": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/dom-matches/download/dom-matches-2.0.0.tgz", - "integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw=", - "dev": true - }, - "dom-scroll-into-view": { - "version": "1.2.1", - "resolved": "http://registry.npm.taobao.org/dom-scroll-into-view/download/dom-scroll-into-view-1.2.1.tgz", - "integrity": "sha1-6PNnMt0ImwIBqI14Fdw/iObWbH4=", - "dev": true - }, - "dom-serializer": { - "version": "0.1.1", - "resolved": "http://registry.npm.taobao.org/dom-serializer/download/dom-serializer-0.1.1.tgz", - "integrity": "sha1-HsQFnihLq+027sKUHUqXChic58A=", - "dev": true, - "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - } - }, - "dom-walk": { - "version": "0.1.1", - "resolved": "http://registry.npm.taobao.org/dom-walk/download/dom-walk-0.1.1.tgz", - "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=", - "dev": true - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/domain-browser/download/domain-browser-1.2.0.tgz", - "integrity": "sha1-PTH1AZGmdJ3RN1p/Ui6CPULlTto=", - "dev": true - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "http://registry.npm.taobao.org/domelementtype/download/domelementtype-1.3.1.tgz", - "integrity": "sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8=", - "dev": true - }, - "domhandler": { - "version": "2.4.2", - "resolved": "http://registry.npm.taobao.org/domhandler/download/domhandler-2.4.2.tgz", - "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.5.1", - "resolved": "http://registry.npm.taobao.org/domutils/download/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "dot-prop": { - "version": "4.2.0", - "resolved": "http://registry.npm.taobao.org/dot-prop/download/dot-prop-4.2.0.tgz", - "integrity": "sha1-HxngwuGqDjJ5fEl5nyg3rGr2nFc=", - "dev": true, - "requires": { - "is-obj": "^1.0.0" - } - }, - "draft-js": { - "version": "0.10.5", - "resolved": "http://registry.npm.taobao.org/draft-js/download/draft-js-0.10.5.tgz", - "integrity": "sha1-v6m+sBj+BTPbsI1mdcNxprCPp0I=", - "dev": true, - "requires": { - "fbjs": "^0.8.15", - "immutable": "~3.7.4", - "object-assign": "^4.1.0" - }, - "dependencies": { - "immutable": { - "version": "3.7.6", - "resolved": "http://registry.npm.taobao.org/immutable/download/immutable-3.7.6.tgz", - "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=", - "dev": true - } - } - }, - "duplexify": { - "version": "3.7.1", - "resolved": "http://registry.npm.taobao.org/duplexify/download/duplexify-3.7.1.tgz", - "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "http://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "echarts": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/echarts/download/echarts-4.2.1.tgz", - "integrity": "sha1-mo6jsDNU+G+CTZdiXDNM8Wll7wM=", - "dev": true, - "requires": { - "zrender": "4.0.7" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.124", - "resolved": "http://registry.npm.taobao.org/electron-to-chromium/download/electron-to-chromium-1.3.124.tgz", - "integrity": "sha1-hh/AFIdIoRs+XM69+LeV/1E/oR8=", - "dev": true - }, - "elliptic": { - "version": "6.4.1", - "resolved": "http://registry.npm.taobao.org/elliptic/download/elliptic-6.4.1.tgz", - "integrity": "sha1-wtC3d2kRuGcixjLDwGxg8vgZk5o=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/emojis-list/download/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "encoding": { - "version": "0.1.12", - "resolved": "http://registry.npm.taobao.org/encoding/download/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true, - "requires": { - "iconv-lite": "~0.4.13" - } - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/end-of-stream/download/end-of-stream-1.4.1.tgz", - "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/enhanced-resolve/download/enhanced-resolve-4.1.0.tgz", - "integrity": "sha1-Qcfgv9/nSsH/4eV61qXGyfN0Kn8=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" - } - }, - "enquire.js": { - "version": "2.1.6", - "resolved": "http://registry.npm.taobao.org/enquire.js/download/enquire.js-2.1.6.tgz", - "integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ=", - "dev": true - }, - "entities": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/entities/download/entities-1.1.2.tgz", - "integrity": "sha1-vfpzUplmTfr9NFKe1PhSKidf6lY=", - "dev": true - }, - "errno": { - "version": "0.1.7", - "resolved": "http://registry.npm.taobao.org/errno/download/errno-0.1.7.tgz", - "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "http://registry.npm.taobao.org/error-ex/download/error-ex-1.3.2.tgz", - "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.13.0", - "resolved": "http://registry.npm.taobao.org/es-abstract/download/es-abstract-1.13.0.tgz", - "integrity": "sha1-rIYUX91QmdjdSVWMy6Lq+biOJOk=", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/es-to-primitive/download/es-to-primitive-1.2.0.tgz", - "integrity": "sha1-7fckeAM0VujdqO8J4ArZZQcH83c=", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "http://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/eslint-scope/download/eslint-scope-4.0.3.tgz", - "integrity": "sha1-ygODMxD2iJoyZHgaqC5j65z+eEg=", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/esprima/download/esprima-4.0.1.tgz", - "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", - "dev": true - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "http://registry.npm.taobao.org/esrecurse/download/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "http://registry.npm.taobao.org/estraverse/download/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/esutils/download/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "http://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "eventemitter3": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/eventemitter3/download/eventemitter3-3.1.0.tgz", - "integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=", - "dev": true - }, - "eventlistener": { - "version": "0.0.1", - "resolved": "http://registry.npm.taobao.org/eventlistener/download/eventlistener-0.0.1.tgz", - "integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg=", - "dev": true - }, - "events": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/events/download/events-3.0.0.tgz", - "integrity": "sha1-mgoN+vYok9krh1uPJpjKQRSXPog=", - "dev": true - }, - "eventsource": { - "version": "1.0.7", - "resolved": "http://registry.npm.taobao.org/eventsource/download/eventsource-1.0.7.tgz", - "integrity": "sha1-j7xyyT/NNAiAkLwKTmT0tc7m2NA=", - "dev": true, - "requires": { - "original": "^1.0.0" - } - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/evp_bytestokey/download/evp_bytestokey-1.0.3.tgz", - "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", - "dev": true, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/execa/download/execa-1.0.0.tgz", - "integrity": "sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg=", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "http://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/expand-tilde/download/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "express": { - "version": "4.16.4", - "resolved": "http://registry.npm.taobao.org/express/download/express-4.16.4.tgz", - "integrity": "sha1-/d72GSYQniTFFeqX/S8b2/Yt8S4=", - "dev": true, - "requires": { - "accepts": "~1.3.5", - "array-flatten": "1.1.1", - "body-parser": "1.18.3", - "content-disposition": "0.5.2", - "content-type": "~1.0.4", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.1.1", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.4", - "qs": "6.5.2", - "range-parser": "~1.2.0", - "safe-buffer": "5.1.2", - "send": "0.16.2", - "serve-static": "1.13.2", - "setprototypeof": "1.1.0", - "statuses": "~1.4.0", - "type-is": "~1.6.16", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "http://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npm.taobao.org/serve-static/download/serve-static-1.13.2.tgz", - "integrity": "sha1-CV6Ecv1bRiN9tQzkhqQ/S4bGzsE=", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" - } - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "http://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz", - "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=", - "dev": true, - "optional": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "http://registry.npm.taobao.org/extglob/download/extglob-2.0.4.tgz", - "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "http://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "faye-websocket": { - "version": "0.10.0", - "resolved": "http://registry.npm.taobao.org/faye-websocket/download/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "fbjs": { - "version": "0.8.17", - "resolved": "http://registry.npm.taobao.org/fbjs/download/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", - "dev": true, - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "http://registry.npm.taobao.org/core-js/download/core-js-1.2.7.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", - "dev": true - } - } - }, - "figgy-pudding": { - "version": "3.5.1", - "resolved": "http://registry.npm.taobao.org/figgy-pudding/download/figgy-pudding-3.5.1.tgz", - "integrity": "sha1-hiRwESkBxyeg5JWoB0S9W6odZ5A=", - "dev": true - }, - "file-loader": { - "version": "5.0.2", - "resolved": "https://registry.npm.taobao.org/file-loader/download/file-loader-5.0.2.tgz?cache=0&sync_timestamp=1574689264559&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffile-loader%2Fdownload%2Ffile-loader-5.0.2.tgz", - "integrity": "sha1-fz2LSshaXo32EzjP7JXXQF+XHKo=", - "dev": true, - "requires": { - "loader-utils": "^1.2.3", - "schema-utils": "^2.5.0" - }, - "dependencies": { - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.10.2.tgz", - "integrity": "sha1-086gTWsBeyiUrWkED+yLYj60vVI=", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "3.4.1", - "resolved": "https://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.4.1.tgz", - "integrity": "sha1-75FuJxxkrBIXH9g4TqrmsjRYVNo=", - "dev": true - }, - "schema-utils": { - "version": "2.6.1", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-2.6.1.tgz?cache=0&sync_timestamp=1574946791935&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-2.6.1.tgz", - "integrity": "sha1-63jwuUXHvPoggrNWXo2zVIAR3E8=", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/fill-range/download/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "finalhandler": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/finalhandler/download/finalhandler-1.1.1.tgz", - "integrity": "sha1-7r9O2EAHnIP0JJA4ydcDAIMBsQU=", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.4.0", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-2.1.0.tgz", - "integrity": "sha1-jQ+UzRP+Q8bHwmGg2GEVypGMBfc=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/find-up/download/find-up-3.0.0.tgz", - "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "findup-sync": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/findup-sync/download/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/flush-write-stream/download/flush-write-stream-1.1.1.tgz", - "integrity": "sha1-jdfYc6G6vCB9lOrQwuDkQnbr8ug=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "follow-redirects": { - "version": "1.7.0", - "resolved": "http://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.7.0.tgz", - "integrity": "sha1-SJ68GY3A5/ZBZ70jsDxMGbV4THY=", - "dev": true, - "requires": { - "debug": "^3.2.6" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz", - "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/for-in/download/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "http://registry.npm.taobao.org/form-data/download/form-data-2.3.3.tgz", - "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", - "dev": true, - "optional": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "http://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "http://registry.npm.taobao.org/fragment-cache/download/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "http://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "from2": { - "version": "2.3.0", - "resolved": "http://registry.npm.taobao.org/from2/download/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "http://registry.npm.taobao.org/fs-write-stream-atomic/download/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.2.8", - "resolved": "http://registry.npm.taobao.org/fsevents/download/fsevents-1.2.8.tgz", - "integrity": "sha1-V+pTIPdizUaW5ejocSDszIsRys8=", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", - "dev": true - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/get-caller-file/download/get-caller-file-1.0.3.tgz", - "integrity": "sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o=", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/get-stream/download/get-stream-4.1.0.tgz", - "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "http://registry.npm.taobao.org/get-value/download/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "http://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "http://registry.npm.taobao.org/glob/download/glob-7.1.3.tgz", - "integrity": "sha1-OWCDLT8VdBCDQtr9OmezMsCWnfE=", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/glob-parent/download/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "global": { - "version": "4.3.2", - "resolved": "http://registry.npm.taobao.org/global/download/global-4.3.2.tgz", - "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", - "dev": true, - "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/global-modules/download/global-modules-1.0.0.tgz", - "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/global-prefix/download/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globby": { - "version": "6.1.0", - "resolved": "http://registry.npm.taobao.org/globby/download/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "http://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "graceful-fs": { - "version": "4.1.15", - "resolved": "http://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.1.15.tgz", - "integrity": "sha1-/7cD4QZuig7qpMi4C6klPu77+wA=", - "dev": true - }, - "gud": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/gud/download/gud-1.0.0.tgz", - "integrity": "sha1-pIlYGxfmpwvsqavjrlfeekmYUsA=", - "dev": true - }, - "hammerjs": { - "version": "2.0.8", - "resolved": "http://registry.npm.taobao.org/hammerjs/download/hammerjs-2.0.8.tgz", - "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=", - "dev": true - }, - "handle-thing": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/handle-thing/download/handle-thing-2.0.0.tgz", - "integrity": "sha1-DgOWlf9QyT/CiFV9aW88HcZ3Z1Q=", - "dev": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "optional": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "http://registry.npm.taobao.org/har-validator/download/har-validator-5.1.3.tgz", - "integrity": "sha1-HvievT5JllV2de7ZiTEQ3DUPoIA=", - "dev": true, - "optional": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/has/download/has-1.0.3.tgz", - "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/has-value/download/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/has-values/download/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.0.4", - "resolved": "http://registry.npm.taobao.org/hash-base/download/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "http://registry.npm.taobao.org/hash.js/download/hash.js-1.1.7.tgz", - "integrity": "sha1-C6vKU46NTuSg+JiNaIZlN6ADz0I=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "he": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/he/download/he-1.2.0.tgz", - "integrity": "sha1-hK5l+n6vsWX922FWauFLrwVmTw8=", - "dev": true - }, - "hex-color-regex": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/hex-color-regex/download/hex-color-regex-1.1.0.tgz", - "integrity": "sha1-TAb8y0YC/iYCs8k9+C1+fb8aio4=", - "dev": true - }, - "history": { - "version": "4.9.0", - "resolved": "http://registry.npm.taobao.org/history/download/history-4.9.0.tgz", - "integrity": "sha1-hFh8IGgDnq2K92np1qaGChT6G8o=", - "dev": true, - "requires": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^2.2.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^0.4.0" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/hmac-drbg/download/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "hoist-non-react-statics": { - "version": "3.3.0", - "resolved": "http://registry.npm.taobao.org/hoist-non-react-statics/download/hoist-non-react-statics-3.3.0.tgz", - "integrity": "sha1-sJF48BIhhPuVrPUl2q7LTY9FlYs=", - "dev": true, - "requires": { - "react-is": "^16.7.0" - } - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/homedir-polyfill/download/homedir-polyfill-1.0.3.tgz", - "integrity": "sha1-dDKYzvTlrz4ZQWH7rcwhUdOgWOg=", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "http://registry.npm.taobao.org/hpack.js/download/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "hsl-regex": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/hsl-regex/download/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", - "dev": true - }, - "hsla-regex": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/hsla-regex/download/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", - "dev": true - }, - "html-comment-regex": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/html-comment-regex/download/html-comment-regex-1.1.2.tgz", - "integrity": "sha1-l9RoiutcgYhqNk+qDK0d2hTUM6c=", - "dev": true - }, - "html-entities": { - "version": "1.2.1", - "resolved": "http://registry.npm.taobao.org/html-entities/download/html-entities-1.2.1.tgz", - "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", - "dev": true - }, - "html-minifier": { - "version": "3.5.21", - "resolved": "http://registry.npm.taobao.org/html-minifier/download/html-minifier-3.5.21.tgz", - "integrity": "sha1-0AQOBUcw41TbAIRjWTGUAVIS0gw=", - "dev": true, - "requires": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" - } - }, - "html-webpack-plugin": { - "version": "3.2.0", - "resolved": "http://registry.npm.taobao.org/html-webpack-plugin/download/html-webpack-plugin-3.2.0.tgz", - "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", - "dev": true, - "requires": { - "html-minifier": "^3.2.3", - "loader-utils": "^0.2.16", - "lodash": "^4.17.3", - "pretty-error": "^2.0.2", - "tapable": "^1.0.0", - "toposort": "^1.0.0", - "util.promisify": "1.0.0" - }, - "dependencies": { - "big.js": { - "version": "3.2.0", - "resolved": "http://registry.npm.taobao.org/big.js/download/big.js-3.2.0.tgz", - "integrity": "sha1-pfwpi4G54Nyi5FiCR4S2XFK6WI4=", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "http://registry.npm.taobao.org/json5/download/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "http://registry.npm.taobao.org/loader-utils/download/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "dev": true, - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" - } - } - } - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "http://registry.npm.taobao.org/htmlparser2/download/htmlparser2-3.10.1.tgz", - "integrity": "sha1-vWedw/WYl7ajS7EHSchVu1OpOS8=", - "dev": true, - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "http://registry.npm.taobao.org/http-deceiver/download/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "http-errors": { - "version": "1.6.3", - "resolved": "http://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "http-parser-js": { - "version": "0.5.0", - "resolved": "http://registry.npm.taobao.org/http-parser-js/download/http-parser-js-0.5.0.tgz", - "integrity": "sha1-1l7b7ehDSdDcMDIIFaFdOcw8u9g=", - "dev": true - }, - "http-proxy": { - "version": "1.17.0", - "resolved": "http://registry.npm.taobao.org/http-proxy/download/http-proxy-1.17.0.tgz", - "integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=", - "dev": true, - "requires": { - "eventemitter3": "^3.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-middleware": { - "version": "0.19.1", - "resolved": "http://registry.npm.taobao.org/http-proxy-middleware/download/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha1-GDx9xKoUeRUDBkmMIQza+WCApDo=", - "dev": true, - "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/https-browserify/download/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz", - "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-replace-symbols": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/icss-replace-symbols/download/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", - "dev": true - }, - "icss-utils": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/icss-utils/download/icss-utils-4.1.0.tgz", - "integrity": "sha1-M527/7n4cpokO3AeHCnUzFjFLw4=", - "dev": true, - "requires": { - "postcss": "^7.0.14" - } - }, - "ieee754": { - "version": "1.1.13", - "resolved": "http://registry.npm.taobao.org/ieee754/download/ieee754-1.1.13.tgz", - "integrity": "sha1-7BaFWOlaoYH9h9N/VcMrvLZwi4Q=", - "dev": true - }, - "iferr": { - "version": "0.1.5", - "resolved": "http://registry.npm.taobao.org/iferr/download/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, - "image-size": { - "version": "0.5.5", - "resolved": "http://registry.npm.taobao.org/image-size/download/image-size-0.5.5.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fimage-size%2Fdownload%2Fimage-size-0.5.5.tgz", - "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", - "dev": true, - "optional": true - }, - "immutable": { - "version": "3.8.2", - "resolved": "http://registry.npm.taobao.org/immutable/download/immutable-3.8.2.tgz", - "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=", - "dev": true - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/import-fresh/download/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/import-local/download/import-local-2.0.0.tgz", - "integrity": "sha1-VQcL44pZk88Y72236WH1vuXFoJ0=", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "http://registry.npm.taobao.org/imurmurhash/download/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/indexes-of/download/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, - "indexof": { - "version": "0.0.1", - "resolved": "http://registry.npm.taobao.org/indexof/download/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "http://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "http://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.5", - "resolved": "http://registry.npm.taobao.org/ini/download/ini-1.3.5.tgz", - "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", - "dev": true - }, - "internal-ip": { - "version": "4.3.0", - "resolved": "http://registry.npm.taobao.org/internal-ip/download/internal-ip-4.3.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Finternal-ip%2Fdownload%2Finternal-ip-4.3.0.tgz", - "integrity": "sha1-hFRSuq2dLKO2nGNaE3rLmg2tCQc=", - "dev": true, - "requires": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" - } - }, - "interpret": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/interpret/download/interpret-1.2.0.tgz", - "integrity": "sha1-1QYaYiS+WOgIOYX1AU2EQ1lXYpY=", - "dev": true - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/invert-kv/download/invert-kv-2.0.0.tgz", - "integrity": "sha1-c5P1r6Weyf9fZ6J2INEcIm4+7AI=", - "dev": true - }, - "ip": { - "version": "1.1.5", - "resolved": "http://registry.npm.taobao.org/ip/download/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/ip-regex/download/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.0", - "resolved": "http://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.9.0.tgz", - "integrity": "sha1-N9905DCg5HVQ/lSi3v4w2KzZX2U=", - "dev": true - }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/is-absolute-url/download/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "http://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/is-binary-path/download/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "http://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", - "dev": true - }, - "is-callable": { - "version": "1.1.4", - "resolved": "http://registry.npm.taobao.org/is-callable/download/is-callable-1.1.4.tgz", - "integrity": "sha1-HhrfIZ4e62hNaR+dagX/DTCiTXU=", - "dev": true - }, - "is-color-stop": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/is-color-stop/download/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "dev": true, - "requires": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/is-date-object/download/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", - "dev": true - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "http://registry.npm.taobao.org/is-directory/download/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "http://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz", - "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/is-number/download/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/is-obj/download/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-path-cwd": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/is-path-cwd/download/is-path-cwd-2.0.0.tgz", - "integrity": "sha1-1Hd6jiJ6AAlqMfAw2zdw+EsRbAI=", - "dev": true - }, - "is-path-in-cwd": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/is-path-in-cwd/download/is-path-in-cwd-2.0.0.tgz", - "integrity": "sha1-aORSpu7CYFAM7CHgKcCkTMDc0uo=", - "dev": true, - "requires": { - "is-path-inside": "^1.0.0" - } - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/is-path-inside/download/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/is-plain-obj/download/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "http://registry.npm.taobao.org/is-plain-object/download/is-plain-object-2.0.4.tgz", - "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.0.4", - "resolved": "http://registry.npm.taobao.org/is-regex/download/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/is-resolvable/download/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/is-stream/download/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-svg": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/is-svg/download/is-svg-3.0.0.tgz", - "integrity": "sha1-kyHb0pwhLlypnE+peUxxS8r6L3U=", - "dev": true, - "requires": { - "html-comment-regex": "^1.1.0" - } - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/is-symbol/download/is-symbol-1.0.2.tgz", - "integrity": "sha1-oFX2rlcZLK7jKeeoYBGLSXqVDzg=", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true, - "optional": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/is-windows/download/is-windows-1.0.2.tgz", - "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/is-wsl/download/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "ismobilejs": { - "version": "0.5.1", - "resolved": "http://registry.npm.taobao.org/ismobilejs/download/ismobilejs-0.5.1.tgz", - "integrity": "sha1-Dj+CXinjL4StXdu2Dp4EqJQEZIg=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "http://registry.npm.taobao.org/isobject/download/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "http://registry.npm.taobao.org/isomorphic-fetch/download/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "dev": true, - "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" - } - }, - "isstream": { - "version": "0.1.2", - "resolved": "http://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true, - "optional": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/js-tokens/download/js-tokens-4.0.0.tgz", - "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "http://registry.npm.taobao.org/js-yaml/download/js-yaml-3.13.1.tgz", - "integrity": "sha1-r/FRswv9+o5J4F2iLnQV6d+jeEc=", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "http://registry.npm.taobao.org/jsbn/download/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/json-parse-better-errors/download/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "http://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true, - "optional": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "http://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "http://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true, - "optional": true - }, - "json2mq": { - "version": "0.2.0", - "resolved": "http://registry.npm.taobao.org/json2mq/download/json2mq-0.2.0.tgz", - "integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=", - "dev": true, - "requires": { - "string-convert": "^0.2.0" - } - }, - "json3": { - "version": "3.3.2", - "resolved": "http://registry.npm.taobao.org/json3/download/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/json5/download/json5-1.0.1.tgz", - "integrity": "sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4=", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "killable": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/killable/download/killable-1.0.1.tgz", - "integrity": "sha1-TIzkQRh6Bhx0dPuHygjipjgZSJI=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", - "dev": true - }, - "last-call-webpack-plugin": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/last-call-webpack-plugin/download/last-call-webpack-plugin-3.0.0.tgz", - "integrity": "sha1-l0LfDhDjz0blwDgcLekNOnotdVU=", - "dev": true, - "requires": { - "lodash": "^4.17.5", - "webpack-sources": "^1.1.0" - } - }, - "lcid": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/lcid/download/lcid-2.0.0.tgz", - "integrity": "sha1-bvXS32DlL4LrIopMNz6NHzlyU88=", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, - "less": { - "version": "3.9.0", - "resolved": "http://registry.npm.taobao.org/less/download/less-3.9.0.tgz", - "integrity": "sha1-t1EcQ/N89X3Iff/ZiD7BISibFHQ=", - "dev": true, - "requires": { - "clone": "^2.1.2", - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "mime": "^1.4.1", - "mkdirp": "^0.5.0", - "promise": "^7.1.1", - "request": "^2.83.0", - "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true, - "optional": true - } - } - }, - "less-loader": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/less-loader/download/less-loader-4.1.0.tgz", - "integrity": "sha1-LBNSxbCaT4QQFJAnT9UWdN5BNj4=", - "dev": true, - "requires": { - "clone": "^2.1.1", - "loader-utils": "^1.1.0", - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "loader-runner": { - "version": "2.4.0", - "resolved": "http://registry.npm.taobao.org/loader-runner/download/loader-runner-2.4.0.tgz", - "integrity": "sha1-7UcGa/5TTX6ExMe5mYwqdWB9k1c=", - "dev": true - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "http://registry.npm.taobao.org/loader-utils/download/loader-utils-1.2.3.tgz", - "integrity": "sha1-H/XcaRHJ8KBiUxpMBLYJQGEIwsc=", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/locate-path/download/locate-path-3.0.0.tgz", - "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.11", - "resolved": "http://registry.npm.taobao.org/lodash/download/lodash-4.17.11.tgz", - "integrity": "sha1-s56mIp72B+zYniyN8SU2iRysm40=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "http://registry.npm.taobao.org/lodash._getnative/download/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "http://registry.npm.taobao.org/lodash.debounce/download/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/lodash.isarguments/download/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "http://registry.npm.taobao.org/lodash.isarray/download/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "http://registry.npm.taobao.org/lodash.keys/download/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "http://registry.npm.taobao.org/lodash.memoize/download/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.throttle": { - "version": "4.1.1", - "resolved": "http://registry.npm.taobao.org/lodash.throttle/download/lodash.throttle-4.1.1.tgz", - "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "http://registry.npm.taobao.org/lodash.uniq/download/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "loglevel": { - "version": "1.6.1", - "resolved": "http://registry.npm.taobao.org/loglevel/download/loglevel-1.6.1.tgz", - "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "http://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz", - "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lower-case": { - "version": "1.1.4", - "resolved": "http://registry.npm.taobao.org/lower-case/download/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", - "dev": true - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "http://registry.npm.taobao.org/lru-cache/download/lru-cache-5.1.1.tgz", - "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/make-dir/download/make-dir-2.1.0.tgz", - "integrity": "sha1-XwMQ4YuL6JjMBwCSlaMK5B6R5vU=", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "mamacro": { - "version": "0.0.3", - "resolved": "http://registry.npm.taobao.org/mamacro/download/mamacro-0.0.3.tgz", - "integrity": "sha1-rSyVdhl8nxq/MI0Hh4Zb2XWj8+Q=", - "dev": true - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "http://registry.npm.taobao.org/map-age-cleaner/download/map-age-cleaner-0.1.3.tgz", - "integrity": "sha1-fVg6cwZDTAVf5HSw9FB45uG0uSo=", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "http://registry.npm.taobao.org/map-cache/download/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/map-visit/download/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "md5.js": { - "version": "1.3.5", - "resolved": "http://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz", - "integrity": "sha1-tdB7jjIW4+J81yjXL3DR5qNCAF8=", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mdn-data": { - "version": "1.1.4", - "resolved": "http://registry.npm.taobao.org/mdn-data/download/mdn-data-1.1.4.tgz", - "integrity": "sha1-ULXU/8RXUnZXPE7tuHgIEqhBnwE=", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "http://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "mem": { - "version": "4.3.0", - "resolved": "http://registry.npm.taobao.org/mem/download/mem-4.3.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fmem%2Fdownload%2Fmem-4.3.0.tgz", - "integrity": "sha1-Rhr0l7xK4JYIzbLmDu+2m/90QXg=", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "http://registry.npm.taobao.org/memory-fs/download/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "http://registry.npm.taobao.org/micromatch/download/micromatch-3.1.10.tgz", - "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/miller-rabin/download/miller-rabin-4.0.1.tgz", - "integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "http://registry.npm.taobao.org/mime/download/mime-1.6.0.tgz", - "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", - "dev": true, - "optional": true - }, - "mime-db": { - "version": "1.39.0", - "resolved": "http://registry.npm.taobao.org/mime-db/download/mime-db-1.39.0.tgz", - "integrity": "sha1-+VogJ1dC99KtBCms/kD0IzVDeA4=", - "dev": true - }, - "mime-types": { - "version": "2.1.23", - "resolved": "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.23.tgz", - "integrity": "sha1-1OrNh96ZNIpoWP4eR5qth3OI2Xc=", - "dev": true, - "requires": { - "mime-db": "~1.39.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/mimic-fn/download/mimic-fn-2.1.0.tgz", - "integrity": "sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs=", - "dev": true - }, - "min-document": { - "version": "2.19.0", - "resolved": "http://registry.npm.taobao.org/min-document/download/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "dev": true, - "requires": { - "dom-walk": "^0.1.0" - } - }, - "mini-css-extract-plugin": { - "version": "0.6.0", - "resolved": "http://registry.npm.taobao.org/mini-css-extract-plugin/download/mini-css-extract-plugin-0.6.0.tgz", - "integrity": "sha1-o/Ezctb83pEvPuTNA5ZlcEgB47k=", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "normalize-url": "^2.0.1", - "schema-utils": "^1.0.0", - "webpack-sources": "^1.1.0" - } - }, - "mini-store": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/mini-store/download/mini-store-2.0.0.tgz", - "integrity": "sha1-CEPASNaULOVePnixtn/AYwIrVIg=", - "dev": true, - "requires": { - "hoist-non-react-statics": "^2.3.1", - "prop-types": "^15.6.0", - "react-lifecycles-compat": "^3.0.4", - "shallowequal": "^1.0.2" - }, - "dependencies": { - "hoist-non-react-statics": { - "version": "2.5.5", - "resolved": "http://registry.npm.taobao.org/hoist-non-react-statics/download/hoist-non-react-statics-2.5.5.tgz", - "integrity": "sha1-xZA89AnA39kI84jmGdhrnBF0y0c=", - "dev": true - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/minimalistic-assert/download/minimalistic-assert-1.0.1.tgz", - "integrity": "sha1-LhlN4ERibUoQ5/f7wAznPoPk1cc=", - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/minimalistic-crypto-utils/download/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "http://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mississippi": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/mississippi/download/mississippi-3.0.0.tgz", - "integrity": "sha1-6goykfl+C16HdrNj1fChLZTGcCI=", - "dev": true, - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mixin-deep": { - "version": "1.3.1", - "resolved": "http://registry.npm.taobao.org/mixin-deep/download/mixin-deep-1.3.1.tgz", - "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "http://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } - }, - "mobx": { - "version": "5.9.4", - "resolved": "http://registry.npm.taobao.org/mobx/download/mobx-5.9.4.tgz", - "integrity": "sha1-He6Sq6M/Z7e67rZ54703ahLlWBI=", - "dev": true - }, - "mobx-react": { - "version": "5.4.3", - "resolved": "http://registry.npm.taobao.org/mobx-react/download/mobx-react-5.4.3.tgz", - "integrity": "sha1-Zwm33YlnDEDpgVkUrCyknMAr+0c=", - "dev": true, - "requires": { - "hoist-non-react-statics": "^3.0.0", - "react-lifecycles-compat": "^3.0.2" - } - }, - "moment": { - "version": "2.24.0", - "resolved": "http://registry.npm.taobao.org/moment/download/moment-2.24.0.tgz", - "integrity": "sha1-DQVdU/UFKqZTyfbraLtdEr9cK1s=", - "dev": true - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/move-concurrently/download/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz", - "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=", - "dev": true - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "http://registry.npm.taobao.org/multicast-dns/download/multicast-dns-6.2.3.tgz", - "integrity": "sha1-oOx72QVcQoL3kMPIL04o2zsxsik=", - "dev": true, - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/multicast-dns-service-types/download/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "mutationobserver-shim": { - "version": "0.3.3", - "resolved": "http://registry.npm.taobao.org/mutationobserver-shim/download/mutationobserver-shim-0.3.3.tgz", - "integrity": "sha1-ZYaWMLyJ17+MnNnLghiM2VWqzSs=", - "dev": true - }, - "nan": { - "version": "2.13.2", - "resolved": "http://registry.npm.taobao.org/nan/download/nan-2.13.2.tgz", - "integrity": "sha1-9R3Hrma6fV1V4ebU2AkugCya7+c=", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "http://registry.npm.taobao.org/nanomatch/download/nanomatch-1.2.13.tgz", - "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "negotiator": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/negotiator/download/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", - "dev": true - }, - "neo-async": { - "version": "2.6.0", - "resolved": "http://registry.npm.taobao.org/neo-async/download/neo-async-2.6.0.tgz", - "integrity": "sha1-udFeTXHGdikIZUtRg+04t1M0CDU=", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "http://registry.npm.taobao.org/nice-try/download/nice-try-1.0.5.tgz", - "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", - "dev": true - }, - "no-case": { - "version": "2.3.2", - "resolved": "http://registry.npm.taobao.org/no-case/download/no-case-2.3.2.tgz", - "integrity": "sha1-YLgTOWvjmz8SiKTB7V0efSi0ZKw=", - "dev": true, - "requires": { - "lower-case": "^1.1.1" - } - }, - "node-fetch": { - "version": "1.7.3", - "resolved": "http://registry.npm.taobao.org/node-fetch/download/node-fetch-1.7.3.tgz", - "integrity": "sha1-mA9vcthSEaU0fGsrwYxbhMPrR+8=", - "dev": true, - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - }, - "node-forge": { - "version": "0.7.5", - "resolved": "http://registry.npm.taobao.org/node-forge/download/node-forge-0.7.5.tgz", - "integrity": "sha1-bBUsNFzhHFL0ZcKr2VfoY5zWdN8=", - "dev": true - }, - "node-libs-browser": { - "version": "2.2.0", - "resolved": "http://registry.npm.taobao.org/node-libs-browser/download/node-libs-browser-2.2.0.tgz", - "integrity": "sha1-xy9g2dRt4IqUDe27JfP/ovm7qnc=", - "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.0", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "0.0.4" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "process": { - "version": "0.11.10", - "resolved": "http://registry.npm.taobao.org/process/download/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true - }, - "punycode": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/punycode/download/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - } - } - }, - "node-releases": { - "version": "1.1.15", - "resolved": "http://registry.npm.taobao.org/node-releases/download/node-releases-1.1.15.tgz", - "integrity": "sha1-nnanOw7KO/eAGt2qDmzpDHlfK5o=", - "dev": true, - "requires": { - "semver": "^5.3.0" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz", - "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", - "dev": true - }, - "normalize-url": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/normalize-url/download/normalize-url-2.0.1.tgz", - "integrity": "sha1-g1qdoVUfom9w6SMpBpojqmV01+Y=", - "dev": true, - "requires": { - "prepend-http": "^2.0.0", - "query-string": "^5.0.1", - "sort-keys": "^2.0.0" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/npm-run-path/download/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "nth-check": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/nth-check/download/nth-check-1.0.2.tgz", - "integrity": "sha1-sr0pXDfj3VijvwcAN2Zjuk2c8Fw=", - "dev": true, - "requires": { - "boolbase": "~1.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/number-is-nan/download/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "http://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.9.0.tgz", - "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=", - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "http://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "http://registry.npm.taobao.org/object-copy/download/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/object-keys/download/object-keys-1.1.1.tgz", - "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/object-visit/download/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "http://registry.npm.taobao.org/object.getownpropertydescriptors/download/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/object.pick/download/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/object.values/download/object.values-1.1.0.tgz", - "integrity": "sha1-v2gQ712j5TJXkOqqK+IT6oRiTak=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/obuf/download/obuf-1.1.2.tgz", - "integrity": "sha1-Cb6jND1BhZ69RGKS0RydTbYZCE4=", - "dev": true - }, - "omit.js": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/omit.js/download/omit.js-1.0.2.tgz", - "integrity": "sha1-kaFPDrqEBm36AVvzDkdMR/MLyFg=", - "dev": true, - "requires": { - "babel-runtime": "^6.23.0" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/on-headers/download/on-headers-1.0.2.tgz", - "integrity": "sha1-dysK5qqlJcOZ5Imt+tkMQD6zwo8=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "http://registry.npm.taobao.org/once/download/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "opn": { - "version": "5.5.0", - "resolved": "http://registry.npm.taobao.org/opn/download/opn-5.5.0.tgz", - "integrity": "sha1-/HFk+rVtI1kExRw7J9pnWMo7m/w=", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, - "optimize-css-assets-webpack-plugin": { - "version": "5.0.1", - "resolved": "http://registry.npm.taobao.org/optimize-css-assets-webpack-plugin/download/optimize-css-assets-webpack-plugin-5.0.1.tgz", - "integrity": "sha1-nrUAcR01FltF5/1gui30DLPrkVk=", - "dev": true, - "requires": { - "cssnano": "^4.1.0", - "last-call-webpack-plugin": "^3.0.0" - } - }, - "original": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/original/download/original-1.0.2.tgz", - "integrity": "sha1-5EKmHP/hxf0gpl8yYcJmY7MD8l8=", - "dev": true, - "requires": { - "url-parse": "^1.4.3" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "http://registry.npm.taobao.org/os-browserify/download/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-locale": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/os-locale/download/os-locale-3.1.0.tgz", - "integrity": "sha1-qAKm7hfyTBBIOrmTVxnO9O0Wvxo=", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "p-defer": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/p-defer/download/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/p-finally/download/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/p-is-promise/download/p-is-promise-2.1.0.tgz", - "integrity": "sha1-kYzrrqJIpiz3/6uOO8qMX4gvxC4=", - "dev": true - }, - "p-limit": { - "version": "2.2.0", - "resolved": "http://registry.npm.taobao.org/p-limit/download/p-limit-2.2.0.tgz", - "integrity": "sha1-QXyZQeYCepq8ulCS3SkE4lW1+8I=", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/p-locate/download/p-locate-3.0.0.tgz", - "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-map": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/p-map/download/p-map-2.1.0.tgz", - "integrity": "sha1-MQko/u+cnsxltosXaTAYpmXOoXU=", - "dev": true - }, - "p-try": { - "version": "2.2.0", - "resolved": "http://registry.npm.taobao.org/p-try/download/p-try-2.2.0.tgz", - "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=", - "dev": true - }, - "pako": { - "version": "1.0.10", - "resolved": "http://registry.npm.taobao.org/pako/download/pako-1.0.10.tgz", - "integrity": "sha1-Qyi621CGpCaqkPVBl31JVdpclzI=", - "dev": true - }, - "parallel-transform": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/parallel-transform/download/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", - "dev": true, - "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "param-case": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/param-case/download/param-case-2.1.1.tgz", - "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", - "dev": true, - "requires": { - "no-case": "^2.2.0" - } - }, - "parse-asn1": { - "version": "5.1.4", - "resolved": "http://registry.npm.taobao.org/parse-asn1/download/parse-asn1-5.1.4.tgz", - "integrity": "sha1-N/Zij4I/vesic7TVQENKIvPvH8w=", - "dev": true, - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/parse-json/download/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/parse-passwd/download/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "parseurl": { - "version": "1.3.3", - "resolved": "http://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz", - "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "http://registry.npm.taobao.org/pascalcase/download/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-browserify": { - "version": "0.0.0", - "resolved": "http://registry.npm.taobao.org/path-browserify/download/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/path-dirname/download/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/path-exists/download/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/path-is-inside/download/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/path-key/download/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "http://registry.npm.taobao.org/path-parse/download/path-parse-1.0.6.tgz", - "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", - "dev": true - }, - "path-to-regexp": { - "version": "1.7.0", - "resolved": "http://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "dev": true, - "requires": { - "isarray": "0.0.1" - } - }, - "pbkdf2": { - "version": "3.0.17", - "resolved": "http://registry.npm.taobao.org/pbkdf2/download/pbkdf2-3.0.17.tgz", - "integrity": "sha1-l2wgZTBhexTrsyEUI597CTNuk6Y=", - "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/pify/download/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "http://registry.npm.taobao.org/pinkie/download/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/pinkie-promise/download/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/pkg-dir/download/pkg-dir-3.0.0.tgz", - "integrity": "sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM=", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "portfinder": { - "version": "1.0.20", - "resolved": "http://registry.npm.taobao.org/portfinder/download/portfinder-1.0.20.tgz", - "integrity": "sha1-vqaGMuVLLhOrewxHdem0G/Jw5Eo=", - "dev": true, - "requires": { - "async": "^1.5.2", - "debug": "^2.2.0", - "mkdirp": "0.5.x" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "http://registry.npm.taobao.org/posix-character-classes/download/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "postcss": { - "version": "7.0.14", - "resolved": "http://registry.npm.taobao.org/postcss/download/postcss-7.0.14.tgz", - "integrity": "sha1-RSftaxyg2CxTzl7BogQcI0a71uU=", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-6.1.0.tgz", - "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-calc": { - "version": "7.0.1", - "resolved": "http://registry.npm.taobao.org/postcss-calc/download/postcss-calc-7.0.1.tgz", - "integrity": "sha1-Ntd7qwI7Dsu5eJ2E3LI8SUEUVDY=", - "dev": true, - "requires": { - "css-unit-converter": "^1.1.1", - "postcss": "^7.0.5", - "postcss-selector-parser": "^5.0.0-rc.4", - "postcss-value-parser": "^3.3.1" - }, - "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/cssesc/download/cssesc-2.0.0.tgz", - "integrity": "sha1-OxO9G7HLNuG8taTc0n9UxdyzVwM=", - "dev": true - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "http://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha1-JJBENWaXsztk8aj3yAki3d7nGVw=", - "dev": true, - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-colormin": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/postcss-colormin/download/postcss-colormin-4.0.3.tgz", - "integrity": "sha1-rgYLzpPteUrHEmTwgTLVUJVr04E=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-convert-values": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/postcss-convert-values/download/postcss-convert-values-4.0.1.tgz", - "integrity": "sha1-yjgT7U2g+BL51DcDWE5Enr4Ymn8=", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-discard-comments": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-discard-comments/download/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha1-H7q9LCRr/2qq15l7KwkY9NevQDM=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-discard-duplicates/download/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha1-P+EzzTyCKC5VD8myORdqkge3hOs=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-empty": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/postcss-discard-empty/download/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha1-yMlR6fc+2UKAGUWERKAq2Qu592U=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/postcss-discard-overridden/download/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha1-ZSrvipZybwKfXj4AFG7npOdV/1c=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "http://registry.npm.taobao.org/postcss-merge-longhand/download/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha1-YvSaE+Sg7gTnuY9CuxYGLKJUniQ=", - "dev": true, - "requires": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - } - }, - "postcss-merge-rules": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/postcss-merge-rules/download/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha1-NivqT/Wh+Y5AdacTxsslrv75plA=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "http://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "dev": true, - "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-minify-font-values/download/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha1-zUw0TM5HQ0P6xdgiBqssvLiv1aY=", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-minify-gradients/download/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha1-k7KcL/UJnFNe7NpWxKpuZlpmNHE=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-minify-params": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-minify-params/download/postcss-minify-params-4.0.2.tgz", - "integrity": "sha1-a5zvAwwR41Jh+V9hjJADbWgNuHQ=", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - } - }, - "postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-minify-selectors/download/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha1-4uXrQL/uUA0M2SQ1APX46kJi+9g=", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "http://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "dev": true, - "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/postcss-modules-extract-imports/download/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha1-gYcZoa4doyX5gyRGsBE27rSTzX4=", - "dev": true, - "requires": { - "postcss": "^7.0.5" - } - }, - "postcss-modules-local-by-default": { - "version": "2.0.6", - "resolved": "http://registry.npm.taobao.org/postcss-modules-local-by-default/download/postcss-modules-local-by-default-2.0.6.tgz", - "integrity": "sha1-3ZlT9t1Ha1/R7y2IMMiSl2C1bmM=", - "dev": true, - "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0", - "postcss-value-parser": "^3.3.1" - } - }, - "postcss-modules-scope": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/postcss-modules-scope/download/postcss-modules-scope-2.1.0.tgz", - "integrity": "sha1-rT9b94VhFPb8q5AbBQLiorw51Os=", - "dev": true, - "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" - } - }, - "postcss-modules-values": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/postcss-modules-values/download/postcss-modules-values-2.0.0.tgz", - "integrity": "sha1-R5tG3Axco9x/pScIUYNrnscVL2Q=", - "dev": true, - "requires": { - "icss-replace-symbols": "^1.1.0", - "postcss": "^7.0.6" - } - }, - "postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/postcss-normalize-charset/download/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha1-izWt067oOhNrBHHg1ZvlilAoXdQ=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-normalize-display-values/download/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha1-Db4EpM6QY9RmftK+R2u4MMglk1o=", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-normalize-positions/download/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha1-BfdX+E8mBDc3g2ipH4ky1LECkX8=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-normalize-repeat-style/download/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha1-xOu8KJ85kaAo1EdRy90RkYsXkQw=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-normalize-string": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-normalize-string/download/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha1-zUTECrB6DHo23F6Zqs4eyk7CaQw=", - "dev": true, - "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-normalize-timing-functions/download/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha1-jgCcoqOUnNr4rSPmtquZy159KNk=", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/postcss-normalize-unicode/download/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha1-hBvUj9zzAZrUuqdJOj02O1KuHPs=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-normalize-url": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/postcss-normalize-url/download/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha1-EOQ3+GvHx+WPe5ZS7YeNqqlfquE=", - "dev": true, - "requires": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "normalize-url": { - "version": "3.3.0", - "resolved": "http://registry.npm.taobao.org/normalize-url/download/normalize-url-3.3.0.tgz", - "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=", - "dev": true - } - } - }, - "postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-normalize-whitespace/download/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha1-vx1AcP5Pzqh9E0joJdjMDF+qfYI=", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-ordered-values": { - "version": "4.1.2", - "resolved": "http://registry.npm.taobao.org/postcss-ordered-values/download/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha1-DPdcgg7H1cTSgBiVWeC1ceusDu4=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/postcss-reduce-initial/download/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha1-f9QuvqXpyBRgljniwuhK4nC6SN8=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-reduce-transforms/download/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha1-F++kBerMbge+NBSlyi0QdGgdTik=", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - } - }, - "postcss-selector-parser": { - "version": "6.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-6.0.2.tgz", - "integrity": "sha1-k0z3mdAWyDQRhZ4J3Oyt4BKG7Fw=", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "postcss-svgo": { - "version": "4.0.2", - "resolved": "http://registry.npm.taobao.org/postcss-svgo/download/postcss-svgo-4.0.2.tgz", - "integrity": "sha1-F7mXvHEbMzurFDqu07jT1uPTglg=", - "dev": true, - "requires": { - "is-svg": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - } - }, - "postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/postcss-unique-selectors/download/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha1-lEaRHzKJv9ZMbWgPBzwDsfnuS6w=", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "http://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/prepend-http/download/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, - "prettier": { - "version": "1.17.0", - "resolved": "http://registry.npm.taobao.org/prettier/download/prettier-1.17.0.tgz", - "integrity": "sha1-U7MDZ27tIswUqfDOwJtHezAmwAg=", - "dev": true - }, - "pretty-error": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/pretty-error/download/pretty-error-2.1.1.tgz", - "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", - "dev": true, - "requires": { - "renderkid": "^2.0.1", - "utila": "~0.4" - } - }, - "process": { - "version": "0.5.2", - "resolved": "http://registry.npm.taobao.org/process/download/process-0.5.2.tgz", - "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.0.tgz", - "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=", - "dev": true - }, - "promise": { - "version": "7.3.1", - "resolved": "http://registry.npm.taobao.org/promise/download/promise-7.3.1.tgz", - "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", - "dev": true, - "requires": { - "asap": "~2.0.3" - } - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/promise-inflight/download/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "prop-types": { - "version": "15.7.2", - "resolved": "http://registry.npm.taobao.org/prop-types/download/prop-types-15.7.2.tgz", - "integrity": "sha1-UsQedbjIfnK52TYOAga5ncv/psU=", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "proxy-addr": { - "version": "2.0.5", - "resolved": "http://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.5.tgz", - "integrity": "sha1-NMvWSi2B9LH9IedvnwbIpFKZ7jQ=", - "dev": true, - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.0" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/prr/download/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, - "psl": { - "version": "1.1.31", - "resolved": "http://registry.npm.taobao.org/psl/download/psl-1.1.31.tgz", - "integrity": "sha1-6aqG0BAbWxBcvpOsa3hM1UcnYYQ=", - "dev": true, - "optional": true - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/public-encrypt/download/public-encrypt-4.0.3.tgz", - "integrity": "sha1-T8ydd6B+SLp1J+fL4N4z0HATMeA=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", - "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "http://registry.npm.taobao.org/pumpify/download/pumpify-1.5.1.tgz", - "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=", - "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/pump/download/pump-2.0.1.tgz", - "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz", - "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", - "dev": true - }, - "q": { - "version": "1.5.1", - "resolved": "http://registry.npm.taobao.org/q/download/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "qs": { - "version": "6.5.2", - "resolved": "http://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz", - "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=", - "dev": true - }, - "query-string": { - "version": "5.1.1", - "resolved": "http://registry.npm.taobao.org/query-string/download/query-string-5.1.1.tgz", - "integrity": "sha1-p4wBK3HBfgXy4/ojGd0zBoLvs8s=", - "dev": true, - "requires": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "querystring": { - "version": "0.2.0", - "resolved": "http://registry.npm.taobao.org/querystring/download/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "http://registry.npm.taobao.org/querystring-es3/download/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true - }, - "querystringify": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/querystringify/download/querystringify-2.1.1.tgz", - "integrity": "sha1-YOWl/WSn+L+k0qsu1v30yFutFU4=", - "dev": true - }, - "raf": { - "version": "3.4.1", - "resolved": "http://registry.npm.taobao.org/raf/download/raf-3.4.1.tgz", - "integrity": "sha1-B0LpmkplUvRF1z4+4DKK8P8e3jk=", - "dev": true, - "requires": { - "performance-now": "^2.1.0" - } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/randombytes/download/randombytes-2.1.0.tgz", - "integrity": "sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "http://registry.npm.taobao.org/randomfill/download/randomfill-1.0.4.tgz", - "integrity": "sha1-ySGW/IarQr6YPxvzF3giSTHWFFg=", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/range-parser/download/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "dev": true - }, - "raw-body": { - "version": "2.3.3", - "resolved": "http://registry.npm.taobao.org/raw-body/download/raw-body-2.3.3.tgz", - "integrity": "sha1-GzJOzmtXBuFThVvBFIxlu39uoMM=", - "dev": true, - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", - "unpipe": "1.0.0" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.23", - "resolved": "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.23.tgz", - "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } - } - }, - "rc-align": { - "version": "2.4.5", - "resolved": "http://registry.npm.taobao.org/rc-align/download/rc-align-2.4.5.tgz", - "integrity": "sha1-yUGlhvWdEBfyOkKPC0aGY/txAqs=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "dom-align": "^1.7.0", - "prop-types": "^15.5.8", - "rc-util": "^4.0.4" - } - }, - "rc-animate": { - "version": "2.6.0", - "resolved": "http://registry.npm.taobao.org/rc-animate/download/rc-animate-2.6.0.tgz", - "integrity": "sha1-yoRA0EJ4GvehMp2E+X6pR5TF7BU=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.6", - "css-animation": "^1.3.2", - "prop-types": "15.x", - "raf": "^3.4.0", - "react-lifecycles-compat": "^3.0.4" - } - }, - "rc-calendar": { - "version": "9.12.4", - "resolved": "http://registry.npm.taobao.org/rc-calendar/download/rc-calendar-9.12.4.tgz", - "integrity": "sha1-aO46hXtTQdeA2Uc1QZJs/gtEkVQ=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "2.x", - "moment": "2.x", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.0", - "rc-util": "^4.1.1", - "react-lifecycles-compat": "^3.0.4" - } - }, - "rc-cascader": { - "version": "0.17.1", - "resolved": "http://registry.npm.taobao.org/rc-cascader/download/rc-cascader-0.17.1.tgz", - "integrity": "sha1-kUSBwzcLX9j4Lk+d+bZZbf7aFNU=", - "dev": true, - "requires": { - "array-tree-filter": "^2.1.0", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.0", - "rc-util": "^4.0.4", - "react-lifecycles-compat": "^3.0.4", - "shallow-equal": "^1.0.0", - "warning": "^4.0.1" - } - }, - "rc-checkbox": { - "version": "2.1.6", - "resolved": "http://registry.npm.taobao.org/rc-checkbox/download/rc-checkbox-2.1.6.tgz", - "integrity": "sha1-XcAGU+UncBjEMf7FXji5HB+XbpA=", - "dev": true, - "requires": { - "babel-runtime": "^6.23.0", - "classnames": "2.x", - "prop-types": "15.x", - "rc-util": "^4.0.4" - } - }, - "rc-collapse": { - "version": "1.11.1", - "resolved": "http://registry.npm.taobao.org/rc-collapse/download/rc-collapse-1.11.1.tgz", - "integrity": "sha1-SqCXetv1Ip19tYIFZGsTkFrdcq0=", - "dev": true, - "requires": { - "classnames": "2.x", - "css-animation": "1.x", - "prop-types": "^15.5.6", - "rc-animate": "2.x", - "react-is": "^16.7.0", - "shallowequal": "^1.1.0" - } - }, - "rc-dialog": { - "version": "7.3.1", - "resolved": "http://registry.npm.taobao.org/rc-dialog/download/rc-dialog-7.3.1.tgz", - "integrity": "sha1-RQQew1v8jjN8kbZLUs6+9upc1KI=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "rc-animate": "2.x", - "rc-util": "^4.4.0" - } - }, - "rc-drawer": { - "version": "1.7.8", - "resolved": "http://registry.npm.taobao.org/rc-drawer/download/rc-drawer-1.7.8.tgz", - "integrity": "sha1-5NBlncIDkJ5f+susimiSbgwiL7U=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "prop-types": "^15.5.0", - "rc-util": "^4.5.1" - } - }, - "rc-dropdown": { - "version": "2.4.1", - "resolved": "http://registry.npm.taobao.org/rc-dropdown/download/rc-dropdown-2.4.1.tgz", - "integrity": "sha1-qu9us6UVLN2ZgolcKnjZtfBGzew=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "classnames": "^2.2.6", - "prop-types": "^15.5.8", - "rc-trigger": "^2.5.1", - "react-lifecycles-compat": "^3.0.2" - } - }, - "rc-editor-core": { - "version": "0.8.9", - "resolved": "http://registry.npm.taobao.org/rc-editor-core/download/rc-editor-core-0.8.9.tgz", - "integrity": "sha1-9hGVLI7tll4+NI2ErnvohdrrIhw=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "classnames": "^2.2.5", - "draft-js": "^0.10.0", - "immutable": "^3.7.4", - "lodash": "^4.16.5", - "prop-types": "^15.5.8", - "setimmediate": "^1.0.5" - } - }, - "rc-editor-mention": { - "version": "1.1.12", - "resolved": "http://registry.npm.taobao.org/rc-editor-mention/download/rc-editor-mention-1.1.12.tgz", - "integrity": "sha1-iWvLFyES8YgS6W/dM7pgPA/HMGo=", - "dev": true, - "requires": { - "babel-runtime": "^6.23.0", - "classnames": "^2.2.5", - "dom-scroll-into-view": "^1.2.0", - "draft-js": "~0.10.0", - "immutable": "^3.7.4", - "prop-types": "^15.5.8", - "rc-animate": "^2.3.0", - "rc-editor-core": "~0.8.3" - } - }, - "rc-form": { - "version": "2.4.4", - "resolved": "http://registry.npm.taobao.org/rc-form/download/rc-form-2.4.4.tgz", - "integrity": "sha1-rA88xkNySZHHQtWuZ0J3f7wLz7s=", - "dev": true, - "requires": { - "async-validator": "~1.8.5", - "babel-runtime": "6.x", - "create-react-class": "^15.5.3", - "dom-scroll-into-view": "1.x", - "hoist-non-react-statics": "^3.3.0", - "lodash": "^4.17.4", - "warning": "^4.0.3" - } - }, - "rc-hammerjs": { - "version": "0.6.9", - "resolved": "http://registry.npm.taobao.org/rc-hammerjs/download/rc-hammerjs-0.6.9.tgz", - "integrity": "sha1-mk3b2hsuyPm5WWCRpqmJhCokOQc=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "hammerjs": "^2.0.8", - "prop-types": "^15.5.9" - } - }, - "rc-input-number": { - "version": "4.4.1", - "resolved": "http://registry.npm.taobao.org/rc-input-number/download/rc-input-number-4.4.1.tgz", - "integrity": "sha1-FjbPKBzejXjqTIuf/P/Xe4A1BnU=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.0", - "prop-types": "^15.5.7", - "rc-util": "^4.5.1", - "rmc-feedback": "^2.0.0" - } - }, - "rc-menu": { - "version": "7.4.22", - "resolved": "http://registry.npm.taobao.org/rc-menu/download/rc-menu-7.4.22.tgz", - "integrity": "sha1-MwVRfMKEuol5pFoNFicXgK2vsu4=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "2.x", - "dom-scroll-into-view": "1.x", - "ismobilejs": "^0.5.1", - "mini-store": "^2.0.0", - "mutationobserver-shim": "^0.3.2", - "prop-types": "^15.5.6", - "rc-animate": "2.x", - "rc-trigger": "^2.3.0", - "rc-util": "^4.1.0", - "resize-observer-polyfill": "^1.5.0" - } - }, - "rc-notification": { - "version": "3.3.1", - "resolved": "http://registry.npm.taobao.org/rc-notification/download/rc-notification-3.3.1.tgz", - "integrity": "sha1-C6o+cPjUCrAVzo+njCYMSQ/HvrQ=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "2.x", - "prop-types": "^15.5.8", - "rc-animate": "2.x", - "rc-util": "^4.0.4" - } - }, - "rc-pagination": { - "version": "1.17.14", - "resolved": "http://registry.npm.taobao.org/rc-pagination/download/rc-pagination-1.17.14.tgz", - "integrity": "sha1-/7KIL9idlbO2A5ONxdsvssMAJtM=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "prop-types": "^15.5.7", - "react-lifecycles-compat": "^3.0.4" - } - }, - "rc-progress": { - "version": "2.3.0", - "resolved": "http://registry.npm.taobao.org/rc-progress/download/rc-progress-2.3.0.tgz", - "integrity": "sha1-z70H/5AmxFAQCYDeIJqSZQ4k8xM=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "prop-types": "^15.5.8" - } - }, - "rc-rate": { - "version": "2.5.0", - "resolved": "http://registry.npm.taobao.org/rc-rate/download/rc-rate-2.5.0.tgz", - "integrity": "sha1-ctSYSgPQp6Dmd5x6ee/OonYmq/Y=", - "dev": true, - "requires": { - "classnames": "^2.2.5", - "prop-types": "^15.5.8", - "rc-util": "^4.3.0", - "react-lifecycles-compat": "^3.0.4" - } - }, - "rc-select": { - "version": "9.0.2", - "resolved": "http://registry.npm.taobao.org/rc-select/download/rc-select-9.0.2.tgz", - "integrity": "sha1-zg0pfbX4pcfou8P8JNntW6ZIASw=", - "dev": true, - "requires": { - "babel-runtime": "^6.23.0", - "classnames": "2.x", - "component-classes": "1.x", - "dom-scroll-into-view": "1.x", - "prop-types": "^15.5.8", - "raf": "^3.4.0", - "rc-animate": "2.x", - "rc-menu": "^7.3.0", - "rc-trigger": "^2.5.4", - "rc-util": "^4.0.4", - "react-lifecycles-compat": "^3.0.2", - "warning": "^4.0.2" - } - }, - "rc-slider": { - "version": "8.6.9", - "resolved": "http://registry.npm.taobao.org/rc-slider/download/rc-slider-8.6.9.tgz", - "integrity": "sha1-syFIpJjJJ8k/INwflehoLEkkv44=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "prop-types": "^15.5.4", - "rc-tooltip": "^3.7.0", - "rc-util": "^4.0.4", - "shallowequal": "^1.0.1", - "warning": "^4.0.3" - } - }, - "rc-steps": { - "version": "3.3.1", - "resolved": "http://registry.npm.taobao.org/rc-steps/download/rc-steps-3.3.1.tgz", - "integrity": "sha1-SHfiiXMx47/ba3ieiK6nj08V9zI=", - "dev": true, - "requires": { - "babel-runtime": "^6.23.0", - "classnames": "^2.2.3", - "lodash": "^4.17.5", - "prop-types": "^15.5.7" - } - }, - "rc-switch": { - "version": "1.9.0", - "resolved": "http://registry.npm.taobao.org/rc-switch/download/rc-switch-1.9.0.tgz", - "integrity": "sha1-qyuHjycTxoE1ikUzkZdsm5WykPc=", - "dev": true, - "requires": { - "classnames": "^2.2.1", - "prop-types": "^15.5.6", - "react-lifecycles-compat": "^3.0.4" - } - }, - "rc-table": { - "version": "6.4.5", - "resolved": "http://registry.npm.taobao.org/rc-table/download/rc-table-6.4.5.tgz", - "integrity": "sha1-siYTeG8Q5Vx+aOvMwYQHoYo8lDE=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "component-classes": "^1.2.6", - "lodash": "^4.17.5", - "mini-store": "^2.0.0", - "prop-types": "^15.5.8", - "rc-util": "^4.0.4", - "react-lifecycles-compat": "^3.0.2", - "shallowequal": "^1.0.2", - "warning": "^3.0.0" - }, - "dependencies": { - "warning": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/warning/download/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - } - } - }, - "rc-tabs": { - "version": "9.6.3", - "resolved": "http://registry.npm.taobao.org/rc-tabs/download/rc-tabs-9.6.3.tgz", - "integrity": "sha1-XuAoFlIXafkuKNwDYKLrEhS1MHU=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "2.x", - "create-react-context": "0.2.2", - "lodash": "^4.17.5", - "prop-types": "15.x", - "raf": "^3.4.1", - "rc-hammerjs": "~0.6.0", - "rc-util": "^4.0.4", - "resize-observer-polyfill": "^1.5.1", - "warning": "^3.0.0" - }, - "dependencies": { - "warning": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/warning/download/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - } - } - }, - "rc-time-picker": { - "version": "3.6.4", - "resolved": "http://registry.npm.taobao.org/rc-time-picker/download/rc-time-picker-3.6.4.tgz", - "integrity": "sha1-P+sF7Ij5yRcB1PaRAl6brZCFrzw=", - "dev": true, - "requires": { - "classnames": "2.x", - "moment": "2.x", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.0" - } - }, - "rc-tooltip": { - "version": "3.7.3", - "resolved": "http://registry.npm.taobao.org/rc-tooltip/download/rc-tooltip-3.7.3.tgz", - "integrity": "sha1-KArsavyqROjf8EgPuv+eh/wArsw=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.2" - } - }, - "rc-tree": { - "version": "1.15.2", - "resolved": "http://registry.npm.taobao.org/rc-tree/download/rc-tree-1.15.2.tgz", - "integrity": "sha1-oNbyD6K9vlHYKdXO6nSkB7BL/qk=", - "dev": true, - "requires": { - "babel-runtime": "^6.23.0", - "classnames": "2.x", - "prop-types": "^15.5.8", - "rc-animate": "^3.0.0-rc.5", - "rc-util": "^4.5.1", - "react-lifecycles-compat": "^3.0.4", - "warning": "^3.0.0" - }, - "dependencies": { - "rc-animate": { - "version": "3.0.0-rc.6", - "resolved": "http://registry.npm.taobao.org/rc-animate/download/rc-animate-3.0.0-rc.6.tgz", - "integrity": "sha1-BCiO76EY4MriFFNsipA/+qwbw/s=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "component-classes": "^1.2.6", - "fbjs": "^0.8.16", - "prop-types": "15.x", - "raf": "^3.4.0", - "rc-util": "^4.5.0", - "react-lifecycles-compat": "^3.0.4" - } - }, - "warning": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/warning/download/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - } - } - }, - "rc-tree-select": { - "version": "2.6.3", - "resolved": "http://registry.npm.taobao.org/rc-tree-select/download/rc-tree-select-2.6.3.tgz", - "integrity": "sha1-N2w2jwvWDSZvJ0C5mrgPGgC9RK0=", - "dev": true, - "requires": { - "classnames": "^2.2.1", - "dom-scroll-into-view": "^1.2.1", - "prop-types": "^15.5.8", - "raf": "^3.4.0", - "rc-animate": "^3.0.0-rc.4", - "rc-tree": "~1.15.0", - "rc-trigger": "^3.0.0-rc.2", - "rc-util": "^4.5.0", - "react-lifecycles-compat": "^3.0.4", - "shallowequal": "^1.0.2", - "warning": "^4.0.1" - }, - "dependencies": { - "rc-animate": { - "version": "3.0.0-rc.6", - "resolved": "http://registry.npm.taobao.org/rc-animate/download/rc-animate-3.0.0-rc.6.tgz", - "integrity": "sha1-BCiO76EY4MriFFNsipA/+qwbw/s=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "component-classes": "^1.2.6", - "fbjs": "^0.8.16", - "prop-types": "15.x", - "raf": "^3.4.0", - "rc-util": "^4.5.0", - "react-lifecycles-compat": "^3.0.4" - } - }, - "rc-trigger": { - "version": "3.0.0-rc.3", - "resolved": "http://registry.npm.taobao.org/rc-trigger/download/rc-trigger-3.0.0-rc.3.tgz", - "integrity": "sha1-NYQt8WdNJTFeFCakSIKkyXZSJYs=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.6", - "prop-types": "15.x", - "raf": "^3.4.0", - "rc-align": "^2.4.1", - "rc-animate": "^3.0.0-rc.1", - "rc-util": "^4.4.0" - } - } - } - }, - "rc-trigger": { - "version": "2.6.2", - "resolved": "http://registry.npm.taobao.org/rc-trigger/download/rc-trigger-2.6.2.tgz", - "integrity": "sha1-qcCbpfrWOvOy7EY0nH22y0ZlcAE=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.6", - "prop-types": "15.x", - "rc-align": "^2.4.0", - "rc-animate": "2.x", - "rc-util": "^4.4.0" - } - }, - "rc-upload": { - "version": "2.6.3", - "resolved": "http://registry.npm.taobao.org/rc-upload/download/rc-upload-2.6.3.tgz", - "integrity": "sha1-mfD0uUjoLHEoClBzme5L8vwWtEA=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "prop-types": "^15.5.7", - "warning": "4.x" - } - }, - "rc-util": { - "version": "4.6.0", - "resolved": "http://registry.npm.taobao.org/rc-util/download/rc-util-4.6.0.tgz", - "integrity": "sha1-ujNyF4MZLsTzr7JZ4YKwTlXet/Y=", - "dev": true, - "requires": { - "add-dom-event-listener": "^1.1.0", - "babel-runtime": "6.x", - "prop-types": "^15.5.10", - "shallowequal": "^0.2.2" - }, - "dependencies": { - "shallowequal": { - "version": "0.2.2", - "resolved": "http://registry.npm.taobao.org/shallowequal/download/shallowequal-0.2.2.tgz", - "integrity": "sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4=", - "dev": true, - "requires": { - "lodash.keys": "^3.1.2" - } - } - } - }, - "react": { - "version": "16.8.6", - "resolved": "http://registry.npm.taobao.org/react/download/react-16.8.6.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Freact%2Fdownload%2Freact-16.8.6.tgz", - "integrity": "sha1-rWw6lhT9Ok6e9REX9U2IjaAfK74=", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.6" - } - }, - "react-hot-loader": { - "version": "4.8.4", - "resolved": "http://registry.npm.taobao.org/react-hot-loader/download/react-hot-loader-4.8.4.tgz", - "integrity": "sha1-NXujQuNn/ULWqHCpwGAcI/oHMMY=", - "dev": true, - "requires": { - "fast-levenshtein": "^2.0.6", - "global": "^4.3.0", - "hoist-non-react-statics": "^3.3.0", - "loader-utils": "^1.1.0", - "lodash": "^4.17.11", - "prop-types": "^15.6.1", - "react-lifecycles-compat": "^3.0.4", - "shallowequal": "^1.0.2", - "source-map": "^0.7.3" - } - }, - "react-is": { - "version": "16.8.6", - "resolved": "http://registry.npm.taobao.org/react-is/download/react-is-16.8.6.tgz", - "integrity": "sha1-W7weLSkUHJ+9/tRWND/ivEMKahY=", - "dev": true - }, - "react-lazy-load": { - "version": "3.0.13", - "resolved": "http://registry.npm.taobao.org/react-lazy-load/download/react-lazy-load-3.0.13.tgz", - "integrity": "sha1-OwqS0zbUPT8Nc8vm81sXBQsIuCQ=", - "dev": true, - "requires": { - "eventlistener": "0.0.1", - "lodash.debounce": "^4.0.0", - "lodash.throttle": "^4.0.0", - "prop-types": "^15.5.8" - } - }, - "react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "http://registry.npm.taobao.org/react-lifecycles-compat/download/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha1-TxonOv38jzSIqMUWv9p4+HI1I2I=", - "dev": true - }, - "react-router": { - "version": "5.0.0", - "resolved": "http://registry.npm.taobao.org/react-router/download/react-router-5.0.0.tgz", - "integrity": "sha1-NJhj92n/wvoQ7nMxpCluhrwSh50=", - "dev": true, - "requires": { - "@babel/runtime": "^7.1.2", - "create-react-context": "^0.2.2", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - } - }, - "react-router-dom": { - "version": "5.0.0", - "resolved": "http://registry.npm.taobao.org/react-router-dom/download/react-router-dom-5.0.0.tgz", - "integrity": "sha1-VCqbhq8mmjfwuHIYxMJeqNzwwHM=", - "dev": true, - "requires": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - } - }, - "react-slick": { - "version": "0.23.2", - "resolved": "http://registry.npm.taobao.org/react-slick/download/react-slick-0.23.2.tgz", - "integrity": "sha1-jYvbx3pmeOitNvUMMleMfA8cVPY=", - "dev": true, - "requires": { - "classnames": "^2.2.5", - "enquire.js": "^2.1.6", - "json2mq": "^0.2.0", - "lodash.debounce": "^4.0.8", - "prettier": "^1.14.3", - "resize-observer-polyfill": "^1.5.0" - } - }, - "readable-stream": { - "version": "3.3.0", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-3.3.0.tgz", - "integrity": "sha1-y4ARqtAC63F78EApH+uoVpyYb7k=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "http://registry.npm.taobao.org/readdirp/download/readdirp-2.2.1.tgz", - "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "http://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.11.1.tgz", - "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", - "dev": true - }, - "regex-not": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/regex-not/download/regex-not-1.0.2.tgz", - "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "http://registry.npm.taobao.org/relateurl/download/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "renderkid": { - "version": "2.0.3", - "resolved": "http://registry.npm.taobao.org/renderkid/download/renderkid-2.0.3.tgz", - "integrity": "sha1-OAF5wv9a4TZcUivy/Pz/AcW3QUk=", - "dev": true, - "requires": { - "css-select": "^1.1.0", - "dom-converter": "^0.2", - "htmlparser2": "^3.3.0", - "strip-ansi": "^3.0.0", - "utila": "^0.4.0" - } - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "http://registry.npm.taobao.org/repeat-element/download/repeat-element-1.1.3.tgz", - "integrity": "sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4=", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "http://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "request": { - "version": "2.88.0", - "resolved": "http://registry.npm.taobao.org/request/download/request-2.88.0.tgz", - "integrity": "sha1-nC/KT301tZLv5Xx/ClXoEFIST+8=", - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/require-main-filename/download/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "resize-observer-polyfill": { - "version": "1.5.1", - "resolved": "http://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz", - "integrity": "sha1-DpAg3T0hAkRY1OvSfiPkAmmBBGQ=", - "dev": true - }, - "resolve": { - "version": "1.10.0", - "resolved": "http://registry.npm.taobao.org/resolve/download/resolve-1.10.0.tgz", - "integrity": "sha1-O9qur0XMB/N1ZW39LlTtCBCxAbo=", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/resolve-cwd/download/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/resolve-dir/download/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/resolve-from/download/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-pathname": { - "version": "2.2.0", - "resolved": "http://registry.npm.taobao.org/resolve-pathname/download/resolve-pathname-2.2.0.tgz", - "integrity": "sha1-fpriHtgV/WOrGJre7mTcgx7vqHk=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "http://registry.npm.taobao.org/resolve-url/download/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "http://registry.npm.taobao.org/ret/download/ret-0.1.15.tgz", - "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", - "dev": true - }, - "rgb-regex": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/rgb-regex/download/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", - "dev": true - }, - "rgba-regex": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/rgba-regex/download/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "http://registry.npm.taobao.org/rimraf/download/rimraf-2.6.3.tgz", - "integrity": "sha1-stEE/g2Psnz54KHNqCYt04M8bKs=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/ripemd160/download/ripemd160-2.0.2.tgz", - "integrity": "sha1-ocGm9iR1FXe6XQeRTLyShQWFiQw=", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rmc-feedback": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/rmc-feedback/download/rmc-feedback-2.0.0.tgz", - "integrity": "sha1-y8bLOuY8emNe7w4l5PuvWsNm7qo=", - "dev": true, - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5" - } - }, - "run-queue": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/run-queue/download/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "dev": true, - "requires": { - "aproba": "^1.1.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "http://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/safe-regex/download/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "http://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "http://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", - "dev": true - }, - "scheduler": { - "version": "0.13.6", - "resolved": "http://registry.npm.taobao.org/scheduler/download/scheduler-0.13.6.tgz", - "integrity": "sha1-RmpOwzJGezGpG5v3TlNHBy5M2Ik=", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/select-hose/download/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "selfsigned": { - "version": "1.10.4", - "resolved": "http://registry.npm.taobao.org/selfsigned/download/selfsigned-1.10.4.tgz", - "integrity": "sha1-zdfsz8pO12NdR6CL8tXTB0CS4s0=", - "dev": true, - "requires": { - "node-forge": "0.7.5" - } - }, - "semver": { - "version": "5.7.0", - "resolved": "http://registry.npm.taobao.org/semver/download/semver-5.7.0.tgz", - "integrity": "sha1-eQp89v6lRZuslhELKbYEEtyP+Ws=", - "dev": true - }, - "send": { - "version": "0.16.2", - "resolved": "http://registry.npm.taobao.org/send/download/send-0.16.2.tgz", - "integrity": "sha1-bsyh4PjBVtFBWXVZhI32RzCmu8E=", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "mime": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/mime/download/mime-1.4.1.tgz", - "integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY=", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "serialize-javascript": { - "version": "1.7.0", - "resolved": "http://registry.npm.taobao.org/serialize-javascript/download/serialize-javascript-1.7.0.tgz", - "integrity": "sha1-1uDfsqODKoyURo5usduX5VoZKmU=", - "dev": true - }, - "serve-index": { - "version": "1.9.1", - "resolved": "http://registry.npm.taobao.org/serve-index/download/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/set-blocking/download/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/set-value/download/set-value-2.0.0.tgz", - "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "http://registry.npm.taobao.org/setimmediate/download/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.0.tgz", - "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", - "dev": true - }, - "sha.js": { - "version": "2.4.11", - "resolved": "http://registry.npm.taobao.org/sha.js/download/sha.js-2.4.11.tgz", - "integrity": "sha1-N6XPC4HsvGlD3hCbopYNGyZYSuc=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shallow-equal": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/shallow-equal/download/shallow-equal-1.1.0.tgz", - "integrity": "sha1-zAIvAw3LoNHBmKv2WKPGx0Thcco=", - "dev": true - }, - "shallowequal": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/shallowequal/download/shallowequal-1.1.0.tgz", - "integrity": "sha1-GI1SHelbkIdAT9TctosT3wrk5/g=", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/shebang-command/download/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/shebang-regex/download/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "http://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "http://registry.npm.taobao.org/simple-swizzle/download/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, - "requires": { - "is-arrayish": "^0.3.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.3.2", - "resolved": "http://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.3.2.tgz", - "integrity": "sha1-RXSirlb3qyBolvtDHq7tBm/fjwM=", - "dev": true - } - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "http://registry.npm.taobao.org/snapdragon/download/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/snapdragon-node/download/snapdragon-node-2.1.1.tgz", - "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "http://registry.npm.taobao.org/snapdragon-util/download/snapdragon-util-3.0.1.tgz", - "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "sockjs": { - "version": "0.3.19", - "resolved": "http://registry.npm.taobao.org/sockjs/download/sockjs-0.3.19.tgz", - "integrity": "sha1-2Xa76ACve9IK4IWY1YI5NQiZPA0=", - "dev": true, - "requires": { - "faye-websocket": "^0.10.0", - "uuid": "^3.0.1" - } - }, - "sockjs-client": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/sockjs-client/download/sockjs-client-1.3.0.tgz", - "integrity": "sha1-EvydbLZj2lc509xftuhofalcsXc=", - "dev": true, - "requires": { - "debug": "^3.2.5", - "eventsource": "^1.0.7", - "faye-websocket": "~0.11.1", - "inherits": "^2.0.3", - "json3": "^3.3.2", - "url-parse": "^1.4.3" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz", - "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "faye-websocket": { - "version": "0.11.1", - "resolved": "http://registry.npm.taobao.org/faye-websocket/download/faye-websocket-0.11.1.tgz", - "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - } - } - }, - "sort-keys": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/sort-keys/download/sort-keys-2.0.0.tgz", - "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/source-list-map/download/source-list-map-2.0.1.tgz", - "integrity": "sha1-OZO9hzv8SEecyp6jpUeDXHwVSzQ=", - "dev": true - }, - "source-map": { - "version": "0.7.3", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.7.3.tgz", - "integrity": "sha1-UwL4FpAxc1ImVECS5kmB91F1A4M=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "http://registry.npm.taobao.org/source-map-resolve/download/source-map-resolve-0.5.2.tgz", - "integrity": "sha1-cuLMNAlVQ+Q7LGKyxMENSpBU8lk=", - "dev": true, - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.12", - "resolved": "http://registry.npm.taobao.org/source-map-support/download/source-map-support-0.5.12.tgz", - "integrity": "sha1-tPOxDVGFelrwE4086AA7IBYT1Zk=", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "http://registry.npm.taobao.org/source-map-url/download/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "spdy": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/spdy/download/spdy-4.0.0.tgz", - "integrity": "sha1-gfIitadDoymqEs6mo5DmDpthPFI=", - "dev": true, - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/spdy-transport/download/spdy-transport-3.0.0.tgz", - "integrity": "sha1-ANSGOmQArXXfkzYaFghgXl3NzzE=", - "dev": true, - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/split-string/download/split-string-3.1.0.tgz", - "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "http://registry.npm.taobao.org/sshpk/download/sshpk-1.16.1.tgz", - "integrity": "sha1-+2YcC+8ps520B2nuOfpwCT1vaHc=", - "dev": true, - "optional": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "ssri": { - "version": "6.0.1", - "resolved": "http://registry.npm.taobao.org/ssri/download/ssri-6.0.1.tgz", - "integrity": "sha1-KjxBso3UW2K2Nnbst0ABJlrp7dg=", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "stable": { - "version": "0.1.8", - "resolved": "http://registry.npm.taobao.org/stable/download/stable-0.1.8.tgz", - "integrity": "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88=", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "http://registry.npm.taobao.org/static-extend/download/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "statuses": { - "version": "1.4.0", - "resolved": "http://registry.npm.taobao.org/statuses/download/statuses-1.4.0.tgz", - "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic=", - "dev": true - }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/stream-browserify/download/stream-browserify-2.0.2.tgz", - "integrity": "sha1-h1IdOKRKp+6RzhzSpH3wy0ndZgs=", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "stream-each": { - "version": "1.2.3", - "resolved": "http://registry.npm.taobao.org/stream-each/download/stream-each-1.2.3.tgz", - "integrity": "sha1-6+J6DDibBPvMIzZClS4Qcxr6m64=", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "http://registry.npm.taobao.org/stream-http/download/stream-http-2.8.3.tgz", - "integrity": "sha1-stJCRpKIpaJ+xP6JM6z2I95lFPw=", - "dev": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "stream-shift": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/stream-shift/download/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", - "dev": true - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true - }, - "string-convert": { - "version": "0.2.1", - "resolved": "http://registry.npm.taobao.org/string-convert/download/string-convert-0.2.1.tgz", - "integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/string-width/download/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string_decoder": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.2.0.tgz", - "integrity": "sha1-/obnOLGVRK/nBGkkOyoe6SQOro0=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/strip-bom/download/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/strip-eof/download/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "style-loader": { - "version": "0.23.1", - "resolved": "http://registry.npm.taobao.org/style-loader/download/style-loader-0.23.1.tgz", - "integrity": "sha1-y5FUYG8+dxq2xKtjcCahBJF02SU=", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0" - } - }, - "stylehacks": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/stylehacks/download/stylehacks-4.0.3.tgz", - "integrity": "sha1-Zxj8r00eB9ihMYaQiB6NlnJqcdU=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "http://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "dev": true, - "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz", - "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "svgo": { - "version": "1.2.2", - "resolved": "http://registry.npm.taobao.org/svgo/download/svgo-1.2.2.tgz", - "integrity": "sha1-AlPTTszyrtStTyg+Ee51GY+dcxY=", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.28", - "css-url-regex": "^1.1.0", - "csso": "^3.5.1", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "dependencies": { - "css-select": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/css-select/download/css-select-2.0.2.tgz", - "integrity": "sha1-q0OGzsnh9miFVWSxfDcztDsqXt4=", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^2.1.2", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "http://registry.npm.taobao.org/domutils/download/domutils-1.7.0.tgz", - "integrity": "sha1-Vuo0HoNOBuZ0ivehyyXaZ+qfjCo=", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - } - } - }, - "tapable": { - "version": "1.1.3", - "resolved": "http://registry.npm.taobao.org/tapable/download/tapable-1.1.3.tgz", - "integrity": "sha1-ofzMBrWNth/XpF2i2kT186Pme6I=", - "dev": true - }, - "terser": { - "version": "3.17.0", - "resolved": "http://registry.npm.taobao.org/terser/download/terser-3.17.0.tgz", - "integrity": "sha1-+I/77aDetWN/nSSw2mb04VqxDLI=", - "dev": true, - "requires": { - "commander": "^2.19.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.10" - }, - "dependencies": { - "commander": { - "version": "2.20.0", - "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.20.0.tgz", - "integrity": "sha1-1YuytcHuj4ew00ACfp6U4iLFpCI=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "terser-webpack-plugin": { - "version": "1.2.3", - "resolved": "http://registry.npm.taobao.org/terser-webpack-plugin/download/terser-webpack-plugin-1.2.3.tgz", - "integrity": "sha1-P5i8kC+sPl0N5zCGn1BmhWEmLsg=", - "dev": true, - "requires": { - "cacache": "^11.0.2", - "find-cache-dir": "^2.0.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "terser": "^3.16.1", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "through2": { - "version": "2.0.5", - "resolved": "http://registry.npm.taobao.org/through2/download/through2-2.0.5.tgz", - "integrity": "sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "thunky": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/thunky/download/thunky-1.0.3.tgz", - "integrity": "sha1-9d9zJFNAewkZHa5z4qjMc/OBqCY=", - "dev": true - }, - "timers-browserify": { - "version": "2.0.10", - "resolved": "http://registry.npm.taobao.org/timers-browserify/download/timers-browserify-2.0.10.tgz", - "integrity": "sha1-HSjj0qrfHVpZlsTp+VYBzQU0gK4=", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, - "timsort": { - "version": "0.3.0", - "resolved": "http://registry.npm.taobao.org/timsort/download/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "tiny-invariant": { - "version": "1.0.4", - "resolved": "http://registry.npm.taobao.org/tiny-invariant/download/tiny-invariant-1.0.4.tgz", - "integrity": "sha1-NGtUFf2Ty2lrDE6Klml/9ZD5JGM=", - "dev": true - }, - "tiny-warning": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/tiny-warning/download/tiny-warning-1.0.2.tgz", - "integrity": "sha1-Hfrnce4aBDlr394no63OvGtkiyg=", - "dev": true - }, - "tinycolor2": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/tinycolor2/download/tinycolor2-1.4.1.tgz", - "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=", - "dev": true - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "http://registry.npm.taobao.org/to-object-path/download/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "http://registry.npm.taobao.org/to-regex/download/to-regex-3.0.2.tgz", - "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/to-regex-range/download/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "toggle-selection": { - "version": "1.0.6", - "resolved": "http://registry.npm.taobao.org/toggle-selection/download/toggle-selection-1.0.6.tgz", - "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=", - "dev": true - }, - "toposort": { - "version": "1.0.7", - "resolved": "http://registry.npm.taobao.org/toposort/download/toposort-1.0.7.tgz", - "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", - "dev": true - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "http://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.4.3.tgz", - "integrity": "sha1-U/Nto/R3g7CSWvoG/587FlKA94E=", - "dev": true, - "optional": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/punycode/download/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true, - "optional": true - } - } - }, - "ts-loader": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.4.5.tgz", - "integrity": "sha512-XYsjfnRQCBum9AMRZpk2rTYSVpdZBpZK+kDh0TeT3kxmQNBDVIeUjdPjY5RZry4eIAb8XHc4gYSUiUWPYvzSRw==", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "enhanced-resolve": "^4.0.0", - "loader-utils": "^1.0.2", - "micromatch": "^3.1.4", - "semver": "^5.0.1" - } - }, - "tsconfig-paths": { - "version": "3.8.0", - "resolved": "http://registry.npm.taobao.org/tsconfig-paths/download/tsconfig-paths-3.8.0.tgz", - "integrity": "sha1-TjQgLVtBlY8mnPVrAe2VuFPVn3I=", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "deepmerge": "^2.0.1", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "tsconfig-paths-webpack-plugin": { - "version": "3.2.0", - "resolved": "http://registry.npm.taobao.org/tsconfig-paths-webpack-plugin/download/tsconfig-paths-webpack-plugin-3.2.0.tgz", - "integrity": "sha1-bnC9QpFa0O+2TTOFFj8MEnDz4E0=", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "enhanced-resolve": "^4.0.0", - "tsconfig-paths": "^3.4.0" - } - }, - "tslib": { - "version": "1.9.3", - "resolved": "http://registry.npm.taobao.org/tslib/download/tslib-1.9.3.tgz", - "integrity": "sha1-1+TdeSRdhUKMTX5IIqeZF5VMooY=", - "dev": true - }, - "tslint": { - "version": "5.16.0", - "resolved": "http://registry.npm.taobao.org/tslint/download/tslint-5.16.0.tgz", - "integrity": "sha1-rmH5xamNKVuaT0VTsbHoMcGYTWc=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^3.2.0", - "glob": "^7.1.1", - "js-yaml": "^3.13.0", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - } - }, - "tslint-react": { - "version": "3.6.0", - "resolved": "http://registry.npm.taobao.org/tslint-react/download/tslint-react-3.6.0.tgz", - "integrity": "sha1-f0YslcSgr6roJQfwZRf/ApQhlqE=", - "dev": true, - "requires": { - "tsutils": "^2.13.1" - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "http://registry.npm.taobao.org/tsutils/download/tsutils-2.29.0.tgz", - "integrity": "sha1-MrSIUBRnrL7dS4VJhnOggSrKC5k=", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "http://registry.npm.taobao.org/tty-browserify/download/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "http://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "http://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-is": { - "version": "1.6.16", - "resolved": "http://registry.npm.taobao.org/type-is/download/type-is-1.6.16.tgz", - "integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.18" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "http://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "typescript": { - "version": "3.4.4", - "resolved": "http://registry.npm.taobao.org/typescript/download/typescript-3.4.4.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Ftypescript%2Fdownload%2Ftypescript-3.4.4.tgz", - "integrity": "sha1-qsSgir7KuAkadfEIQv+gYxgY94U=", - "dev": true - }, - "ua-parser-js": { - "version": "0.7.19", - "resolved": "http://registry.npm.taobao.org/ua-parser-js/download/ua-parser-js-0.7.19.tgz", - "integrity": "sha1-lBUb5MCn+x0AGvcCL9rKRkJlnks=", - "dev": true - }, - "uglify-js": { - "version": "3.4.10", - "resolved": "http://registry.npm.taobao.org/uglify-js/download/uglify-js-3.4.10.tgz", - "integrity": "sha1-mtlWPY6zrN+404WX0q8dgV9qdV8=", - "dev": true, - "requires": { - "commander": "~2.19.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.19.0.tgz", - "integrity": "sha1-9hmKqE5bg8RgVLlN3tv+1e6f8So=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "union-value": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/union-value/download/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "http://registry.npm.taobao.org/set-value/download/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/uniq/download/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "uniqs": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/uniqs/download/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", - "dev": true - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/unique-filename/download/unique-filename-1.1.1.tgz", - "integrity": "sha1-HWl2k2mtoFgxA6HmrodoG1ZXMjA=", - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/unique-slug/download/unique-slug-2.0.1.tgz", - "integrity": "sha1-Xp7cbRzo+yZNsYpQfvm9hURFHKY=", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "unquote": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/unquote/download/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/unset-value/download/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "http://registry.npm.taobao.org/has-value/download/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/isobject/download/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "http://registry.npm.taobao.org/has-values/download/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } - } - }, - "upath": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/upath/download/upath-1.1.2.tgz", - "integrity": "sha1-PbZYYA7a7sy+bbXmhNZ+6MKs0Gg=", - "dev": true - }, - "upper-case": { - "version": "1.1.3", - "resolved": "http://registry.npm.taobao.org/upper-case/download/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", - "dev": true - }, - "uri-js": { - "version": "4.2.2", - "resolved": "http://registry.npm.taobao.org/uri-js/download/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "http://registry.npm.taobao.org/urix/download/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url": { - "version": "0.11.0", - "resolved": "http://registry.npm.taobao.org/url/download/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "http://registry.npm.taobao.org/punycode/download/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, - "url-parse": { - "version": "1.4.6", - "resolved": "http://registry.npm.taobao.org/url-parse/download/url-parse-1.4.6.tgz", - "integrity": "sha1-uvkdbmeDyKeV60dokv/vJzf8BFY=", - "dev": true, - "requires": { - "querystringify": "^2.0.0", - "requires-port": "^1.0.0" - } - }, - "use": { - "version": "3.1.1", - "resolved": "http://registry.npm.taobao.org/use/download/use-3.1.1.tgz", - "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8=", - "dev": true - }, - "util": { - "version": "0.11.1", - "resolved": "http://registry.npm.taobao.org/util/download/util-0.11.1.tgz", - "integrity": "sha1-MjZzNyDsZLsn9uJvQhqqLhtYjWE=", - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/util.promisify/download/util.promisify-1.0.0.tgz", - "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "utila": { - "version": "0.4.0", - "resolved": "http://registry.npm.taobao.org/utila/download/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "3.3.2", - "resolved": "http://registry.npm.taobao.org/uuid/download/uuid-3.3.2.tgz", - "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=", - "dev": true - }, - "v8-compile-cache": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/v8-compile-cache/download/v8-compile-cache-2.0.2.tgz", - "integrity": "sha1-pCiyi7JnkHNMT8i8n6EG/M6/amw=", - "dev": true - }, - "value-equal": { - "version": "0.4.0", - "resolved": "http://registry.npm.taobao.org/value-equal/download/value-equal-0.4.0.tgz", - "integrity": "sha1-xb3S9U7gk8BIOdcc4uR1imiQq8c=", - "dev": true - }, - "vary": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "vendors": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/vendors/download/vendors-1.0.2.tgz", - "integrity": "sha1-f8te759WI7FWvOqJ7DfWNnbyGAE=", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "http://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "http://registry.npm.taobao.org/vm-browserify/download/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } - }, - "warning": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/warning/download/warning-4.0.3.tgz", - "integrity": "sha1-Fungd+uKhtavfWSqHgX9hbRnjKM=", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "watchpack": { - "version": "1.6.0", - "resolved": "http://registry.npm.taobao.org/watchpack/download/watchpack-1.6.0.tgz", - "integrity": "sha1-S8EsLr6KonenHx0/FNaFx7RGzQA=", - "dev": true, - "requires": { - "chokidar": "^2.0.2", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "http://registry.npm.taobao.org/wbuf/download/wbuf-1.7.3.tgz", - "integrity": "sha1-wdjRSTFtPqhShIiVy2oL/oh7h98=", - "dev": true, - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "webpack": { - "version": "4.30.0", - "resolved": "http://registry.npm.taobao.org/webpack/download/webpack-4.30.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack%2Fdownload%2Fwebpack-4.30.0.tgz", - "integrity": "sha1-rKdu91YwoixJ/MI1s5tMV1kdM6k=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-module-context": "1.8.5", - "@webassemblyjs/wasm-edit": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5", - "acorn": "^6.0.5", - "acorn-dynamic-import": "^4.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^1.0.0", - "tapable": "^1.1.0", - "terser-webpack-plugin": "^1.1.0", - "watchpack": "^1.5.0", - "webpack-sources": "^1.3.0" - } - }, - "webpack-cli": { - "version": "3.3.0", - "resolved": "http://registry.npm.taobao.org/webpack-cli/download/webpack-cli-3.3.0.tgz", - "integrity": "sha1-VcinTK4eiBF/ndo6gBxycuk8oxg=", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "enhanced-resolve": "^4.1.0", - "findup-sync": "^2.0.0", - "global-modules": "^1.0.0", - "import-local": "^2.0.0", - "interpret": "^1.1.0", - "loader-utils": "^1.1.0", - "supports-color": "^5.5.0", - "v8-compile-cache": "^2.0.2", - "yargs": "^12.0.5" - } - }, - "webpack-dev-middleware": { - "version": "3.6.2", - "resolved": "http://registry.npm.taobao.org/webpack-dev-middleware/download/webpack-dev-middleware-3.6.2.tgz", - "integrity": "sha1-83onrXwJzX3GfNl2VUE6uqH1WUI=", - "dev": true, - "requires": { - "memory-fs": "^0.4.1", - "mime": "^2.3.1", - "range-parser": "^1.0.3", - "webpack-log": "^2.0.0" - }, - "dependencies": { - "mime": { - "version": "2.4.2", - "resolved": "http://registry.npm.taobao.org/mime/download/mime-2.4.2.tgz", - "integrity": "sha1-zlIppemf/DE6usgGtILBDnumrHg=", - "dev": true - } - } - }, - "webpack-dev-server": { - "version": "3.3.1", - "resolved": "http://registry.npm.taobao.org/webpack-dev-server/download/webpack-dev-server-3.3.1.tgz", - "integrity": "sha1-cEbkne1cElWoLF2UK83aVStypi0=", - "dev": true, - "requires": { - "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.1.5", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.0", - "express": "^4.16.4", - "html-entities": "^1.2.1", - "http-proxy-middleware": "^0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.2.0", - "ip": "^1.1.5", - "killable": "^1.0.1", - "loglevel": "^1.6.1", - "opn": "^5.5.0", - "portfinder": "^1.0.20", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.4", - "semver": "^6.0.0", - "serve-index": "^1.9.1", - "sockjs": "0.3.19", - "sockjs-client": "1.3.0", - "spdy": "^4.0.0", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.6.2", - "webpack-log": "^2.0.0", - "yargs": "12.0.5" - }, - "dependencies": { - "semver": { - "version": "6.0.0", - "resolved": "http://registry.npm.taobao.org/semver/download/semver-6.0.0.tgz", - "integrity": "sha1-BeNZ7lceWtftZBpu7B5Ue6Ut6mU=", - "dev": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-6.1.0.tgz", - "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "webpack-log": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/webpack-log/download/webpack-log-2.0.0.tgz", - "integrity": "sha1-W3ko4GN1k/EZ0y9iJ8HgrDHhtH8=", - "dev": true, - "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - } - }, - "webpack-sources": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/webpack-sources/download/webpack-sources-1.3.0.tgz", - "integrity": "sha1-KijcufH0X+lg2PFJMlK17mUw+oU=", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "websocket-driver": { - "version": "0.7.0", - "resolved": "http://registry.npm.taobao.org/websocket-driver/download/websocket-driver-0.7.0.tgz", - "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", - "dev": true, - "requires": { - "http-parser-js": ">=0.4.0", - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.3", - "resolved": "http://registry.npm.taobao.org/websocket-extensions/download/websocket-extensions-0.1.3.tgz", - "integrity": "sha1-XS/yKXcAPsaHpLhwc9+7rBRszyk=", - "dev": true - }, - "whatwg-fetch": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/whatwg-fetch/download/whatwg-fetch-3.0.0.tgz", - "integrity": "sha1-/IBORYzEYACbGiuWa8iBfSV4rvs=", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "http://registry.npm.taobao.org/which/download/which-1.3.1.tgz", - "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "worker-farm": { - "version": "1.6.0", - "resolved": "http://registry.npm.taobao.org/worker-farm/download/worker-farm-1.6.0.tgz", - "integrity": "sha1-rsxAWXb6talVJhgIRvDboojzpKA=", - "dev": true, - "requires": { - "errno": "~0.1.7" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-2.1.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fwrap-ansi%2Fdownload%2Fwrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/string-width/download/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xtend": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/xtend/download/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/y18n/download/y18n-4.0.0.tgz", - "integrity": "sha1-le+U+F7MgdAHwmThkKEg8KPIVms=", - "dev": true - }, - "yallist": { - "version": "3.0.3", - "resolved": "http://registry.npm.taobao.org/yallist/download/yallist-3.0.3.tgz", - "integrity": "sha1-tLBJ4xS+VF486AIjbWzSLNkcPek=", - "dev": true - }, - "yargs": { - "version": "12.0.5", - "resolved": "http://registry.npm.taobao.org/yargs/download/yargs-12.0.5.tgz", - "integrity": "sha1-BfWZe2CWR7ZPZrgeO0sQo2jnrRM=", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "http://registry.npm.taobao.org/yargs-parser/download/yargs-parser-11.1.1.tgz", - "integrity": "sha1-h5oIZZc7yp9rq1y987HGfsfTvPQ=", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "zrender": { - "version": "4.0.7", - "resolved": "https://registry.npm.taobao.org/zrender/download/zrender-4.0.7.tgz", - "integrity": "sha1-Fa6WCCL17+1BCZXTflEH/j3hDm0=", - "dev": true - } - } -} diff --git a/console/src/container/admin-consume/detail.tsx b/console/src/container/admin-consume/detail.tsx deleted file mode 100644 index 0d9183f0..00000000 --- a/console/src/container/admin-consume/detail.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import * as React from 'react'; - -import { PaginationConfig, Table } from 'component/antd'; -import { observer } from 'mobx-react'; -import urlQuery from 'store/url-query'; -import { IConsumeInfo } from 'store/topic'; -import { consume } from 'store/consume'; -import { SearchAndFilter } from 'container/cluster-topic'; -import { modal } from 'store'; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class AdminConsume extends SearchAndFilter { - public state = { - searchKey: '', - }; - - public columns = [{ - title: '消费组名称', - dataIndex: 'consumerGroup', - key: 'consumerGroup', - width: '70%', - sorter: (a: IConsumeInfo, b: IConsumeInfo) => a.consumerGroup.charCodeAt(0) - b.consumerGroup.charCodeAt(0), - }, { - title: 'location', - dataIndex: 'location', - key: 'location', - width: '20%', - render: (t: string) => t.toLowerCase(), - }, { - title: '操作', - key: 'operation', - width: '10%', - render: (t: string, r: IConsumeInfo) => { - return ( - 详情); - }, - }, - ]; - - public componentDidMount() { - consume.getConsumeInfo(urlQuery.clusterId); - } - - public render() { - const data = consume.data.filter((d) => d.consumerGroup.includes(this.state.searchKey)); - return ( - <> -
    - {this.renderSearch('请输入消费组名称')} -
-
- - - - ); - } -} diff --git a/console/src/container/admin-consume/index.less b/console/src/container/admin-consume/index.less deleted file mode 100644 index 5e1b9a42..00000000 --- a/console/src/container/admin-consume/index.less +++ /dev/null @@ -1,8 +0,0 @@ -.content-container .table-operation-bar.in-panel { - position: static; - text-align: right; - .new-topic { - margin-right: 0; - margin-left: 30px; - } -} \ No newline at end of file diff --git a/console/src/container/admin-consume/index.tsx b/console/src/container/admin-consume/index.tsx deleted file mode 100644 index 8b2edcb9..00000000 --- a/console/src/container/admin-consume/index.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import * as React from 'react'; - -import { PaginationConfig, Table } from 'component/antd'; -import { observer } from 'mobx-react'; -import urlQuery from 'store/url-query'; -import { IConsumeInfo } from 'store/topic'; -import { consume } from 'store/consume'; -import { SearchAndFilter } from 'container/cluster-topic'; -import { modal } from 'store'; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class AdminConsume extends SearchAndFilter { - public state = { - searchKey: '', - }; - - public columns = [{ - title: '消费组名称', - dataIndex: 'consumerGroup', - key: 'consumerGroup', - width: '70%', - sorter: (a: IConsumeInfo, b: IConsumeInfo) => a.consumerGroup.charCodeAt(0) - b.consumerGroup.charCodeAt(0), - }, { - title: 'location', - dataIndex: 'location', - key: 'location', - width: '20%', - render: (t: string) => t.toLowerCase(), - }, { - title: '操作', - key: 'operation', - width: '10%', - render: (t: string, r: IConsumeInfo) => { - return ( - 详情); - }, - }, - ]; - - public componentDidMount() { - consume.getConsumeInfo(urlQuery.clusterId); - } - - public render() { - const data = consume.data.filter((d) => d.consumerGroup.includes(this.state.searchKey)); - return ( -
-
    - {this.renderSearch('请输入消费组名称')} -
-
-
- - - ); - } -} diff --git a/console/src/container/admin-controller/index.tsx b/console/src/container/admin-controller/index.tsx deleted file mode 100644 index ca51f281..00000000 --- a/console/src/container/admin-controller/index.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import * as React from 'react'; - -import { Table, Tabs, PaginationConfig } from 'component/antd'; -import { observer } from 'mobx-react'; -import urlQuery from 'store/url-query'; -import { controller } from 'store/controller'; -import { SearchAndFilter } from 'container/cluster-topic'; -import moment from 'moment'; - -const TabPane = Tabs.TabPane; - -const columns = [ - { - title: 'BrokerId', - dataIndex: 'brokerId', - key: 'brokerId', - sorter: (a: any, b: any) => a.brokerNum - b.brokerNum, - }, - { - title: 'host', - key: 'host', - dataIndex: 'host', - render: (r: string, t: any) => { - return ( - {r} - - ); }, - }, - { - title: '版本', - dataIndex: 'controllerVersion', - key: 'controllerVersion', - }, - { - title: '变更时间', - dataIndex: 'controllerTimestamp', - key: 'controllerTimestamp', - sorter: (a: any, b: any) => a.controllerTimestamp - b.updacontrollerTimestampteTime, - render: (t: number) => moment(t).format('YYYY-MM-DD HH:mm:ss'), - }, -]; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class AdminController extends SearchAndFilter { - public state = { - searchKey: '', - }; - - public componentDidMount() { - controller.getController(urlQuery.clusterId); - } - - public renderController() { - if (!controller.data) return null; - const data = controller.data.filter((d) => d.host.includes(this.state.searchKey)); - return ( -
- ); - } - - public render() { - return ( - <> -
    - {this.renderSearch('请输入关键词')} -
- - - {this.renderController()} - - - - ); - } -} diff --git a/console/src/container/admin-home/cluster-detail.tsx b/console/src/container/admin-home/cluster-detail.tsx deleted file mode 100644 index 2ef7d617..00000000 --- a/console/src/container/admin-home/cluster-detail.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import * as React from 'react'; - -import urlQuery from 'store/url-query'; -import { NetWorkFlow } from 'container/topic-detail/com'; -import { Tabs } from 'component/antd'; -import { broker } from 'store/broker'; -import { BrokerStatus } from 'container/broker-info/base-info'; -import { BrokerList } from 'container/broker-info/base-info'; -import { AdminConsume } from 'container/admin-consume'; -import { AdminRegion } from 'container/admin-region'; -import { AdminController } from 'container/admin-controller'; -import AdminTopic from 'container/admin-topic/index'; -import { handleTabKey } from 'lib/utils'; - -export class ClusterDetail extends React.Component { - - public updateStatus = () => { - broker.getBrokerNetwork(urlQuery.clusterId); - } - public componentDidMount() { - this.updateStatus(); - } - public render() { - return ( - <> - - -
-

历史流量

- -
-
-

实时流量

- - 刷新 - - -
-
- - - - - - - - - - - - - - - -
- - - ); - } -} diff --git a/console/src/container/admin-home/index.less b/console/src/container/admin-home/index.less deleted file mode 100644 index 8987ee75..00000000 --- a/console/src/container/admin-home/index.less +++ /dev/null @@ -1,9 +0,0 @@ -.right-flow { - .k-abs { - right: 24px; - cursor: pointer; - & > i { - margin-right: 5px; - } - } -} diff --git a/console/src/container/admin-home/index.tsx b/console/src/container/admin-home/index.tsx deleted file mode 100644 index a53d9df3..00000000 --- a/console/src/container/admin-home/index.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import * as React from 'react'; -import './index.less'; - -import { Table, Tabs, ColumnProps, PaginationConfig } from 'component/antd'; - -import { modal } from 'store'; -import { cluster } from 'store/cluster'; -import { observer } from 'mobx-react'; -import { IClusterData } from 'types/base-type'; - -const TabPane = Tabs.TabPane; - -const detailUrl = '/admin/cluster_detail?clusterId='; - -const collectionColumns: Array> = [ - { - title: '集群ID', - dataIndex: 'clusterId', - key: 'clusterId', - sorter: (a: IClusterData, b: IClusterData) => a.clusterId - b.clusterId, - }, - { - title: '集群名称', - key: 'clusterName', - sorter: (a: IClusterData, b: IClusterData) => a.clusterName.charCodeAt(0) - b.clusterName.charCodeAt(0), - render: (text, record) => { - const url = `${detailUrl}${record.clusterId}&clusterName=${record.clusterName}`; - return {record.clusterName}; - }, - }, - { - title: 'Topic 数', - key: 'topicNum', - sorter: (a: IClusterData, b: IClusterData) => a.topicNum - b.topicNum, - render: (text, record) => { - return {record.topicNum}; - }, - }, - { - title: 'Broker 数量', - dataIndex: 'brokerNum', - key: 'brokerNum', - sorter: (a: IClusterData, b: IClusterData) => a.brokerNum - b.brokerNum, - render: (text, record) => { - return ( - - {record.brokerNum} - ); - }, - }, - { - title: 'ConsumerGroup 数', - key: 'consumerGroupNum', - sorter: (a: IClusterData, b: IClusterData) => a.consumerGroupNum - b.consumerGroupNum, - render: (text, record) => { - return {record.consumerGroupNum}; - }, - }, - { - title: 'Region 数', - key: 'regionNum', - sorter: (a: IClusterData, b: IClusterData) => a.regionNum - b.regionNum, - render: (text, record) => { - return {record.regionNum}; - }, - }, - { - title: 'ControllerID', - key: 'controllerId', - sorter: (a: IClusterData, b: IClusterData) => a.controllerId - b.controllerId, - render: (text, record) => { - return {record.controllerId}; - }, - }, - { - title: '操作', - dataIndex: 'operation', - key: 'operation', - render: (text, record) => { - return ( - - 修改 - - ); - }, - }, -]; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class AdminHome extends React.Component { - public renderList() { - return ( -
- ); - } - - public componentDidMount() { - cluster.getClusters(); - cluster.getKafkaVersions(); - } - - public render() { - return ( - <> -
    -
  • - 添加集群 -
  • -
- - - {this.renderList()} - - - - ); - } -} diff --git a/console/src/container/admin-operation/index.tsx b/console/src/container/admin-operation/index.tsx deleted file mode 100644 index 4fb17ac1..00000000 --- a/console/src/container/admin-operation/index.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import * as React from 'react'; - -import { Table, Tabs, Modal, notification } from 'component/antd'; -import { PaginationConfig } from 'antd/es/table/interface'; -import { modal } from 'store'; -import { observer } from 'mobx-react'; -import { operation, ITask, taskMap } from 'store/operation'; -import { cluster } from 'store/cluster'; -import moment from 'moment'; -import { modifyTask } from 'lib/api'; -import { SearchAndFilter } from 'container/cluster-topic'; -import { tableFilter } from 'lib/utils'; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class AdminOperation extends SearchAndFilter { - public state = { - searchKey: '', - filterClusterVisible: false, - filterStatusVisible: false, - }; - - public renderColumns = (data: ITask[]) => { - const cluster = Object.assign({ - title: '集群名称', - dataIndex: 'clusterName', - key: 'clusterId', - filters: tableFilter(data, 'clusterName'), - onFilter: (value: string, record: ITask) => record.clusterName.indexOf(value) === 0, - }, this.renderColumnsFilter('filterClusterVisible')); - - const status = Object.assign({ - title: '状态', - dataIndex: 'status', - key: 'status', - filters: taskMap.map((ele, index) => ({ text: ele, value: index + '' })), - onFilter: (value: string, record: ITask) => record.status === +value, - render: (t: number) => {taskMap[t]}, - }, this.renderColumnsFilter('filterStatusVisible')); - - return [ - { - title: '任务id', - dataIndex: 'taskId', - key: 'taskId', - sorter: (a: ITask, b: ITask) => a.taskId - b.taskId, - }, - cluster, - { - title: 'Topic名称', - dataIndex: 'topicName', - key: 'topicName', - sorter: (a: ITask, b: ITask) => a.topicName.charCodeAt(0) - b.topicName.charCodeAt(0), - }, - { - title: '创建人', - dataIndex: 'operator', - key: 'operator', - sorter: (a: ITask, b: ITask) => a.operator.charCodeAt(0) - b.operator.charCodeAt(0), - }, - { - title: '创建时间', - dataIndex: 'gmtCreate', - key: 'gmtCreate', - sorter: (a: ITask, b: ITask) => a.gmtCreate - b.gmtCreate, - render: (t: number) => moment(t).format('YYYY-MM-DD HH:mm:ss'), - }, - status, - { - title: '操作', - dataIndex: 'operation', - key: 'operation', - width: 200, - render: (text: string, record: ITask) => { - const status: number = record.status; - return ( - - 详情 - {+status === 0 || +status === 1 ? 修改 : null} - {!status ? 执行 : null} - {!status ? 撤销 : null} - - ); - }, - }, - ]; - } - - public handleAction(taskId: number, type: string) { - Modal.confirm({ - title: `确认${type === 'start' ? '执行Topic迁移任务' : '撤销任务' + taskId}`, - okText: '确定', - cancelText: '取消', - onOk: () => { - modifyTask({ action: type, taskId }).then(() => { - notification.success({ message: `${type === 'start' ? '执行' : '撤销'}任务成功` }); - operation.getTask(); - }); - }, - }); - } - - public componentDidMount() { - operation.getTask(); - cluster.getClusters(); - } - - public render() { - const { searchKey } = this.state; - const data: ITask[] = operation.tasks && searchKey ? operation.tasks.filter((d) => d.taskId === +searchKey) : operation.tasks; - return ( - <> -
    -
  • - 新建迁移任务 -
  • - {this.renderSearch('请输入关键字')} -
- - -
- - - - ); - } -} diff --git a/console/src/container/admin-order/index.less b/console/src/container/admin-order/index.less deleted file mode 100644 index 9edaa9da..00000000 --- a/console/src/container/admin-order/index.less +++ /dev/null @@ -1,16 +0,0 @@ -.num-container { - position: relative; - .num { - position: absolute; - width: 15px; - height: 15px; - line-height: 15px; - border-radius: 15px; - background-color: #f5222d; - color: #fff; - display: inline-block; - right: -18px; - text-align: center; - top: -1px; - } -} diff --git a/console/src/container/admin-order/index.tsx b/console/src/container/admin-order/index.tsx deleted file mode 100644 index 5251e1d1..00000000 --- a/console/src/container/admin-order/index.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import * as React from 'react'; - -import { Table, Tabs } from 'component/antd'; -import { PaginationConfig } from 'antd/es/table/interface'; -import { modal } from 'store'; -import { observer } from 'mobx-react'; -import { order, tableStatusFilter } from 'store/order'; -import moment from 'moment'; -import { handleTabKey, tableFilter } from 'lib/utils'; -import { SearchAndFilter } from 'container/cluster-topic'; -import { IBaseOrder } from 'types/base-type'; - -import './index.less'; - -const TabPane = Tabs.TabPane; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class AdminOrder extends SearchAndFilter { - public state = { - searchKey: '', - filterClusterVisible: false, - filterStatusVisible: false, - filterSVisible: false, - filterCVisible: false, - }; - - public componentDidMount() { - order.getAdminOrder(); - } - - public renderColumns = (data: IBaseOrder[], type: boolean) => { - const cluster = Object.assign({ - title: '集群名称', - dataIndex: 'clusterName', - key: 'clusterName', - filters: tableFilter(data, 'clusterName'), - onFilter: (value: string, record: IBaseOrder) => record.clusterName.indexOf(value) === 0, - }, this.renderColumnsFilter(type ? 'filterClusterVisible' : 'filterCVisible')); - - const status = Object.assign({ - title: '审批状态', - dataIndex: 'statusStr', - key: 'statusStr', - width: 100, - filters: tableStatusFilter, - onFilter: (value: string, record: IBaseOrder) => record.statusStr.indexOf(value) === 0, - render: (t: string) => {t}, - }, this.renderColumnsFilter(type ? 'filterStatusVisible' : 'filterSVisible')); - return [ - { - title: '工单 ID', - dataIndex: 'orderId', - key: 'orderId', - sorter: (a: IBaseOrder, b: IBaseOrder) => a.orderId - b.orderId, - }, - cluster, - { - title: 'Topic 名称', - dataIndex: 'topicName', - key: 'topicName', - sorter: (a: IBaseOrder, b: IBaseOrder) => a.topicName.charCodeAt(0) - b.topicName.charCodeAt(0), - }, - { - title: '申请人', - dataIndex: 'applicant', - key: 'applicant', - sorter: (a: IBaseOrder, b: IBaseOrder) => a.applicant.charCodeAt(0) - b.applicant.charCodeAt(0), - }, - { - title: '审批人', - dataIndex: 'approver', - key: 'approver', - }, - { - title: '申请时间', - dataIndex: 'gmtCreate', - key: 'gmtCreate', - sorter: (a: IBaseOrder, b: IBaseOrder) => a.gmtCreate - b.gmtCreate, - render: (t: number) => moment(t).format('YYYY-MM-DD HH:mm:ss'), - }, - status, - { - title: '操作', - dataIndex: 'operation', - key: 'operation', - width: 100, - render: (text: string, r: IBaseOrder) => { - if (!+location.hash.substr(1)) { - return ( - - 详情 - {r.orderStatus === 0 ? 审批 : null} - - ); - } else { - return ( - - 详情 - {r.orderStatus === 0 ? 审批 : null} - - ); - } - }, - }, - ]; - } - - public renderTopic() { - const data = order.adminTopicOrder.filter((d) => d.topicName.includes(this.state.searchKey)); - return ( -
- ); - } - - public renderPartition() { - const data = order.adminPartitionOrder.filter((d) => d.topicName.includes(this.state.searchKey)); - return ( -
- ); - } - - public render() { - const defaultKey = location.hash.substr(1) || '0'; - return ( - <> -
    - {this.renderSearch('请输入topic名称')} -
- - - {order.pendingTopic ? {order.pendingTopic} : null} - Topic 申请 - - } - > - {this.renderTopic()} - - - {order.pendingOrder ? {order.pendingOrder} : null} - 扩容申请 - - } - key="1" - > - {this.renderPartition()} - - - - ); - } -} diff --git a/console/src/container/admin-region/index.tsx b/console/src/container/admin-region/index.tsx deleted file mode 100644 index bfed9637..00000000 --- a/console/src/container/admin-region/index.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import * as React from 'react'; - -import { Table, Tabs, Modal, PaginationConfig, notification } from 'component/antd'; -import { modal } from 'store'; -import { observer } from 'mobx-react'; -import { IRegionData, region, statusMap, levelMap } from 'store/region'; -import urlQuery from 'store/url-query'; -import { SearchAndFilter } from 'container/cluster-topic'; - -const TabPane = Tabs.TabPane; - -const handleDeleteRegion = (record: IRegionData) => { - Modal.confirm({ - title: `确认删除 ${record.regionName} ?`, - okText: '确定', - cancelText: '取消', - onOk: () => { - region.delRegion(record.regionId).then(() => { - notification.success({ message: '删除成功' }); - region.getRegions(urlQuery.clusterId); - }); - }, - }); -}; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class AdminRegion extends SearchAndFilter { - public state = { - searchKey: '', - filterStatus: false, - filterLevel: false, - }; - - public renderColumns = () => { - const status = Object.assign({ - title: '状态', - dataIndex: 'status', - key: 'status', - filters: statusMap.map((ele, index) => ({ text: ele, value: index + '' })), - render: (t: number) => {statusMap[t + 1]}, - onFilter: (value: string, record: IRegionData) => record.status + 1 === +value, - }, this.renderColumnsFilter('filterStatus')); - - const level = Object.assign({ - title: '重要程度', - dataIndex: 'level', - key: 'level', - filters: levelMap.map((ele, index) => ({ text: ele, value: index + '' })), - render: (t: number) => { - return levelMap[t]; - }, - onFilter: (value: string, record: IRegionData) => record.level === +value, - }, this.renderColumnsFilter('filterLevel')); - - return [ - { - title: 'Region名称', - dataIndex: 'regionName', - key: 'regionName', - }, - { - title: 'BrokerList', - key: 'brokerIdList', - render: (text: string, record: IRegionData) => { - return {record.brokerIdList.join(', ')}; - }, - }, - { - title: '操作者', - dataIndex: 'operator', - key: 'operator', - }, - status, - level, - { - title: '备注', - dataIndex: 'description', - key: 'description', - }, - { - title: '操作', - dataIndex: 'operation', - key: 'operation', - width: 200, - render: (text: string, record: IRegionData) => { - return ( - - 编辑 - 删除 - - ); - }, - }, - ]; - } - - public componentDidMount() { - region.getRegions(urlQuery.clusterId); - } - - public renderRegion() { - if (!region.data) return null; - const data = region.data.filter((d) => d.regionName.includes(this.state.searchKey)); - return ( -
- ); - } - - public render() { - return ( - <> -
    -
  • - 新增Region -
  • - {this.renderSearch('请输入关键词')} -
- - - {this.renderRegion()} - - - - ); - } -} diff --git a/console/src/container/admin-topic/index.tsx b/console/src/container/admin-topic/index.tsx deleted file mode 100644 index aa3e36cc..00000000 --- a/console/src/container/admin-topic/index.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import * as React from 'react'; - -import { Table, Tabs, Form, notification, Modal, Tooltip } from 'component/antd'; -import { PaginationConfig } from 'antd/es/table/interface'; -import { UserHome } from 'container/user-home'; -import { topic } from 'store/topic'; -import urlQuery from 'store/url-query'; -import { modal } from 'store'; -import { observer } from 'mobx-react'; -import { deleteTopic } from 'lib/api'; -import { cluster } from 'store/cluster'; -import { ITopic } from 'types/base-type'; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -class AdminTopic extends UserHome { - - public cols = [ - { - title: 'Topic名称', - dataIndex: 'topicName', - key: 'topicName', - width: 350, - onCell: () => ({ - style: { - maxWidth: 250, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - cursor: 'pointer', - }, - }), - sorter: (a: ITopic, b: ITopic) => a.topicName.charCodeAt(0) - b.topicName.charCodeAt(0), - render: (t: string, r: ITopic) => { - return {t}; - }, - }, - { - title: '分区数', - dataIndex: 'partitionNum', - key: 'partitionNum', - sorter: (a: ITopic, b: ITopic) => b.partitionNum - a.partitionNum, - }, - { - title: '副本数', - dataIndex: 'replicaNum', - key: 'replicaNum', - sorter: (a: ITopic, b: ITopic) => b.replicaNum - a.replicaNum, - }, - { - title: '流入 (KB/s)', - dataIndex: 'byteIn', - key: 'byteIn', - sorter: (a: ITopic, b: ITopic) => b.byteIn - a.byteIn, - render: (t: number) => (t / 1024).toFixed(2), - }, - { - title: '流入(QPS)', - dataIndex: 'produceRequest', - key: 'produceRequest', - width: 150, - sorter: (a: ITopic, b: ITopic) => b.produceRequest - a.produceRequest, - render: (t: number) => t.toFixed(2), - }, - { - title: '负责人', - dataIndex: 'principals', - key: 'principals', - width: 120, - onCell: () => ({ - style: { - maxWidth: 100, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - cursor: 'pointer', - }, - }), - render: (t: string) => {t}, - sorter: (a: ITopic, b: ITopic) => - a.principals && b.principals ? a.principals.charCodeAt(0) - b.principals.charCodeAt(0) : (-1), - }, - { - title: '操作', - dataIndex: 'operation', - key: 'operation', - width: 200, - render: (text: string, r: ITopic) => { - return ( - - 扩分区 - 编辑 - 删除 - - ); - }, - }, - ]; - - public handleDelete = ({ clusterId, topicName }: ITopic) => { - const topicNameList = [topicName]; - Modal.confirm({ - title: `确认删除${topicName}?`, - okText: '确定', - cancelText: '取消', - onOk: () => { - deleteTopic({ clusterId, topicNameList }).then(() => { - notification.success({ message: '删除成功' }); - topic.getAdminTopics(urlQuery.clusterId); - }); - }, - }); - } - - public renderTable() { - - return ( - <> - - -
- - - - ); - } - - public componentDidMount() { - cluster.getClusters(); - topic.getAdminTopics(urlQuery.clusterId); - } - - public renderClusterTopic() { - return ( - <> - {this.renderSearch('请输入Topic名称或者负责人')} - - ); - } -} - -export default Form.create({ name: 'aminTopic' })(AdminTopic); diff --git a/console/src/container/admin-usermanage/index.less b/console/src/container/admin-usermanage/index.less deleted file mode 100644 index 1c637537..00000000 --- a/console/src/container/admin-usermanage/index.less +++ /dev/null @@ -1,12 +0,0 @@ -.u-container { - width: 100%; - height: 48px; - background: rgba(0,0,0,0.02); - display: flex; - justify-content: space-between; - vertical-align: middle; - line-height: 48px; - padding: 0 12px; - margin-top: 20px; - position: relative; -} diff --git a/console/src/container/admin-usermanage/index.tsx b/console/src/container/admin-usermanage/index.tsx deleted file mode 100644 index 7bb4c47c..00000000 --- a/console/src/container/admin-usermanage/index.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import * as React from 'react'; - -import { Table, notification, PaginationConfig, Modal } from 'component/antd'; -import { observer } from 'mobx-react'; -import { users } from 'store/users'; -import { deleteUser } from 'lib/api'; -import { modal } from 'store'; -import { SearchAndFilter } from 'container/cluster-topic'; -import './index.less'; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -const handleForbidden = (record: any) => { - Modal.confirm({ - title: `确认删除 ${record.username} ?`, - okText: '确定', - cancelText: '取消', - onOk: () => { - deleteUser(record.username).then(() => { - notification.success({ message: '删除成功' }); - users.getUsers(); - }); - }, - }); -}; - -@observer -export class UserManage extends SearchAndFilter { - public state = { - searchKey: '', - filterVisible: false, - }; - - public renderColumns = () => { - const role = Object.assign({ - title: '角色', - key: 'roleName', - dataIndex: 'roleName', - filters: users.filterRole, - onFilter: (value: string, record: any) => record.roleName.indexOf(value) === 0, - }, this.renderColumnsFilter('filterVisible')); - - return [ - { - title: '用户名', - dataIndex: 'username', - key: 'username', - }, - role, - { - title: '操作', - dataIndex: 'operation', - key: 'operation', - render: (t: any, r: any) => { - return ( - - 修改 - 删除 - - ); - }, - }, - ]; - } - - public componentDidMount() { - users.getUsers(); - } - - public render() { - const data = users.userData.filter((d) => d.username.includes(this.state.searchKey)); - return ( - <> -
- 管理员授权 -
    -
  • - 新建用户 -
  • - {this.renderSearch('用户名称')} -
-
-
- - ); - } -} diff --git a/console/src/container/alarm/index.tsx b/console/src/container/alarm/index.tsx deleted file mode 100644 index 8c5a2703..00000000 --- a/console/src/container/alarm/index.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import * as React from 'react'; - -import { Table, Tabs, Select, Input, notification, Modal } from 'component/antd'; -import { PaginationConfig } from 'antd/es/table/interface'; -import { modal } from 'store'; -import { observer } from 'mobx-react'; -import { alarm, IAlarm } from 'store/alarm'; -import { deleteAlarm } from 'lib/api'; -import { SearchAndFilter } from 'container/cluster-topic'; -import { getCookie } from 'lib/utils'; -import moment = require('moment'); - -const TabPane = Tabs.TabPane; -const Search = Input.Search; - -const handleDeleteAlarm = (record: IAlarm) => { - Modal.confirm({ - title: `确认删除 ${record.alarmName} ?`, - okText: '确定', - cancelText: '取消', - onOk: () => { - deleteAlarm(record.id).then(() => { - notification.success({ message: '删除成功' }); - alarm.getAlarm(); - }); - }, - }); -}; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class Alarm extends SearchAndFilter { - public state = { - searchKey: '', - filterVisible: false, - }; - - public componentDidMount() { - alarm.getAlarm(); - alarm.getAlarmConstant(); - } - - public renderColumns = () => { - const status = Object.assign({ - title: '状态', - dataIndex: 'status', - key: 'status', - filters: [{ text: '已启用', value: '1' }, { text: '暂停', value: '0' }], - onFilter: (value: string, record: IAlarm) => record.status === +value, - render: (t: string) => {t ? '已启用' : '暂停'}, - }, this.renderColumnsFilter('filterVisible')); - - return [ - { - title: '配置名称', - dataIndex: 'alarmName', - key: 'alarmName', - sorter: (a: IAlarm, b: IAlarm) => a.alarmName.charCodeAt(0) - b.alarmName.charCodeAt(0), - }, - { - title: '负责人', - dataIndex: 'principalList', - key: 'principalList', - render: (t: string[]) => t.join(','), - }, - { - title: '创建时间', - dataIndex: 'gmtCreate', - key: 'gmtCreate', - sorter: (a: IAlarm, b: IAlarm) => a.gmtCreate - b.gmtCreate, - render: (t: number) => moment(t).format('YYYY-MM-DD HH:mm:ss'), - }, - status, - { - title: '操作', - dataIndex: 'operation', - key: 'operation', - width: 200, - render: (text: string, record: IAlarm) => { - return ( - - 修改 - 删除 - - ); - }, - }, - ]; - } - - public renderAlarm() { - const data = alarm.data.filter((d) => { - return d.alarmName.includes(this.state.searchKey) || d.principalList.includes(this.state.searchKey); - }); - return ( -
- ); - } - - public handleModify = (record: IAlarm) => { - if (!getCookie('username') && !record.principalList.includes(getCookie('username'))) { - notification.success({ message: '抱歉,没有修改权限' }); - return false; - } - modal.showAlarmModify(record); - } - - public render() { - return ( - <> -
    -
  • - 添加告警配置 -
  • - {this.renderSearch('请输入关键字')} -
- - - {this.renderAlarm()} - - - - ); - } -} diff --git a/console/src/container/broker-detail/base-detail.tsx b/console/src/container/broker-detail/base-detail.tsx deleted file mode 100644 index 88c9cfe0..00000000 --- a/console/src/container/broker-detail/base-detail.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import * as React from 'react'; -import { TopicDetail } from 'container/topic-detail'; -import './index.less'; -import { broker, IBrokerNetworkInfo } from 'store/broker'; -import { observer } from 'mobx-react'; -import { StatusGraghCom } from 'component/flow-table'; -import urlQuery from 'store/url-query'; -import { NetWorkFlow } from 'container/topic-detail/com'; - -@observer -export class OneBrokerStatus extends StatusGraghCom { - public getData() { - return broker.oneNetwork; - } -} - -export class BrokerBaseDetail extends TopicDetail { - public componentDidMount() { - broker.getOneBrokerNetwork(urlQuery.clusterId, urlQuery.brokerId); - broker.getBrokerTopicAnalyzer(urlQuery.clusterId, urlQuery.brokerId); - } - - public render() { - return ( - <> -
-

基本信息

- -
-
-

历史流量

- -
-
-

实时流量

- 刷新 - -
- - ); - } -} - -@observer -class Summary extends React.Component { - public componentDidMount() { - broker.getBrokerBaseInfo(urlQuery.clusterId, urlQuery.brokerId); - } - - public render() { - return ( -
-
-
主机:{broker.brokerBaseInfo.host}
-
启动时间:{broker.brokerBaseInfo.startTime}
-
-
-
- Topic数 -

{broker.brokerBaseInfo.topicNum}

-
-
- 分区数 -

{broker.brokerBaseInfo.partitionCount}

-
-
- 分区Leader -

{broker.brokerBaseInfo.leaderCount}

-
-
- Port -

{broker.brokerBaseInfo.port}

-
-
- JMX Port -

{broker.brokerBaseInfo.jmxPort}

-
-
-
- ); - } -} diff --git a/console/src/container/broker-detail/broker-index.tsx b/console/src/container/broker-detail/broker-index.tsx deleted file mode 100644 index fdf4dbb9..00000000 --- a/console/src/container/broker-detail/broker-index.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import React from 'react'; -import { observer } from 'mobx-react'; -import { broker } from 'store/broker'; -import urlQuery from 'store/url-query'; -import echarts from 'echarts/lib/echarts'; -import { getBrokerMetricOption } from 'lib/charts-config'; -import { MetricChartList as list } from './constant'; -import { Spin, DatePicker, notification, Button } from 'component/antd'; -import './index.less'; - -// 引入柱状图 -import 'echarts/lib/chart/line'; -// 引入提示框和标题组件 -import 'echarts/lib/component/tooltip'; -import 'echarts/lib/component/title'; -import 'echarts/lib/component/legend'; -import moment from 'moment'; - -@observer -export class BrokerMetrics extends React.Component { - public chartId: HTMLDivElement[] = []; - public charts: echarts.ECharts[] = []; - - public state = { - loading: true, - }; - - public renderCharts(startTime: moment.Moment, endTime: moment.Moment) { - broker.getBrokerKeyMetrics(urlQuery.clusterId, urlQuery.brokerId, - startTime.format('x'), - endTime.format('x')).then(data => { - getBrokerMetricOption(list, data).forEach((ele: object, index) => { - if (ele) { - this.charts[index] = echarts.init(this.chartId[index]); - this.charts[index].setOption(ele); - this.setState({ loading: false }); - } - this.charts[index] = null; - }); - }); - } - - public componentDidMount() { - this.renderCharts(broker.startTime, broker.endTime); - } - - public handleSearch = () => { - const { startTime, endTime } = broker; - if (startTime >= endTime) { - notification.error({ message: '开始时间不能大于或等于结束时间' }); - return false; - } - this.setState({ loading: true }); - this.renderCharts(startTime, endTime); - } - - public render() { - const charts = list.map((item, index) => { - if (!item.value) return
this.chartId.push(id)} />; - return ( -
-

{item.label}

- -
this.chartId.push(id)} /> - -
- ); - }); - return ( - <> -
-
    -
  • - 开始时间 - -
  • -
  • - 结束时间 - -
  • -
  • -
-
-
- {charts} -
- - ); - } -} diff --git a/console/src/container/broker-detail/broker-partition.tsx b/console/src/container/broker-detail/broker-partition.tsx deleted file mode 100644 index 428b83c3..00000000 --- a/console/src/container/broker-detail/broker-partition.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import React from 'react'; -import { Table, PaginationConfig } from 'component/antd'; -import { observer } from 'mobx-react'; -import { broker, IPartitions } from 'store/broker'; -import { columsDefault } from './constant'; -import urlQuery from 'store/url-query'; -import './index.less'; - -const columns = [{ - title: 'Topic', - dataIndex: 'topicName', - key: 'topicName', -}, { - title: 'Leader', - dataIndex: 'leaderPartitionList', - onCell: () => ({ - style: { - maxWidth: 250, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - cursor: 'pointer', - }, - }), - render: (value: number[]) => { - return value.map(i => {i}); - }, -}, { - title: '副本', - dataIndex: 'followerPartitionIdList', - onCell: () => ({ - style: { - maxWidth: 250, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - cursor: 'pointer', - }, - }), - render: (value: number[]) => { - return value.map(i => {i}); - }, -}, { - title: '未同步副本', - dataIndex: 'notUnderReplicatedPartitionIdList', - render: (value: number[]) => { - return value.map(i => {i}); - }, -}, { - title: '状态', - dataIndex: 'underReplicated', - render: (value: boolean) => { - return value ? '已同步' : '未同步'; - }, -}, { - title: '操作', - render: (record: IPartitions) => { - return (查看详情); - }, -}, -]; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class BrokerPartition extends React.Component { - - public componentDidMount() { - broker.getPartitions(urlQuery.clusterId, urlQuery.brokerId); - } - - public getDescription = (value: any, record: IPartitions) => { - return Object.keys(value).map((key: keyof IPartitions) => { - return ( -

{value[key]}{(record[key] as []).join(',')} - (共{(record[key] as []).length}个)

); - }); - } - - public getMoreDetail = (record: IPartitions) => { - return ( -
-

Topic: {record.topicName}

-

isUnderReplicated:{record.underReplicated ? '已同步' : '未同步'}

- {this.getDescription(columsDefault, record)} -
- ); - } - - public render() { - return ( -
- ); - } -} diff --git a/console/src/container/broker-detail/constant.ts b/console/src/container/broker-detail/constant.ts deleted file mode 100644 index 434672ed..00000000 --- a/console/src/container/broker-detail/constant.ts +++ /dev/null @@ -1,64 +0,0 @@ -export const MetricChartList = [ - { - value: 'requestHandlerIdlPercent', - label: '请求处理器空闲百分比(%)', - }, - { - value: 'networkProcessorIdlPercent', - label: '网络处理器空闲百分比(%)', - }, - { - value: 'requestQueueSize', - label: '请求列表大小(个)', - }, - { - value: 'responseQueueSize', - label: '响应列表大小(个)', - }, - { - value: 'logFlushTime', - label: '刷日志时间(ms)', - }, - { - value: '', - label: '', - }, - { - value: 'totalTimeProduceMean', - label: 'produce请求时间-平均值(ms)', - }, - { - value: 'totalTimeFetchConsumerMean', - label: 'fetch请求处理时间-平均值(ms)', - }, - { - value: 'totalTimeProduce99Th', - label: 'produce请求时间-99分位(ms)', - }, - { - value: 'totalTimeFetchConsumer99Th', - label: 'fetch请求处理时间-99分位(ms)', - }, - { - value: 'failProduceRequest', - label: '每秒生产失败数(条/秒)', - }, - { - value: 'failFetchRequest', - label: '每秒消费失败数(条/秒)', - }, -]; - -export const columsDefault = { - leaderPartitionList: 'leaderPartitions:', - followerPartitionIdList: 'followerPartitions:', - notUnderReplicatedPartitionIdList: 'notUnderReplicatedPartitions:', -}; - -export const brokerMetrics = { - bytesIn: 'Bytes In(MB/ 秒)', - bytesOut: 'Bytes Out(MB/ 秒)', - messagesIn: 'Messages In(条)', - totalFetchRequests: 'Total Fetch Requests(QPS)', - totalProduceRequests: 'Total Produce Requests(QPS)', -}; diff --git a/console/src/container/broker-detail/index.tsx b/console/src/container/broker-detail/index.tsx deleted file mode 100644 index ffc4dc44..00000000 --- a/console/src/container/broker-detail/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import * as React from 'react'; -import { Tabs } from 'component/antd'; -import { BrokerBaseDetail } from './base-detail'; -import { TopicAnalysis } from './topic-analysis'; -import { BrokerTopicInfo } from './topic-info'; -import { BrokerPartition } from './broker-partition'; -import { BrokerMetrics } from './broker-index'; -import { handleTabKey } from 'lib/utils'; - -const TabPane = Tabs.TabPane; - -export class BrokerDetail extends React.Component { - public render() { - return ( - - - - - - - - - - - {/* - - */} - - - - - - - - ); - } -} diff --git a/console/src/container/broker-detail/topic-analysis.tsx b/console/src/container/broker-detail/topic-analysis.tsx deleted file mode 100644 index 57eb787c..00000000 --- a/console/src/container/broker-detail/topic-analysis.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import * as React from 'react'; -import { Table } from 'component/antd'; -import urlQuery from 'store/url-query'; -import { broker, IBrokerMetrics } from 'store/broker'; -import { brokerMetrics } from './constant'; -import { observer } from 'mobx-react'; - -const columns = [{ - title: 'Topic名称', - dataIndex: 'topicName', - key: 'topicName', -}, -{ - title: 'Bytes In(MB/s)', - dataIndex: 'bytesInRate', - key: 'bytesInRate', - render: (t: number, record: any) => `${record && record.bytesIn} (${+Math.ceil((t * 100))}%)`, -}, -{ - title: 'Bytes Out(MB/s)', - dataIndex: 'bytesOutRate', - key: 'bytesOutRate', - render: (t: number, record: any) => `${record && record.bytesOut} (${+Math.ceil((t * 100))}%)`, -}, -{ - title: 'Message In(秒)', - dataIndex: 'messagesInRate', - key: 'messagesInRate', - render: (t: number, record: any) => `${record && record.messagesIn} (${+Math.ceil((t * 100))}%)`, -}, -{ - title: 'Total Fetch Requests(秒)', - dataIndex: 'totalFetchRequestsRate', - key: 'totalFetchRequestsRate', - render: (t: number, record: any) => `${record && record.totalFetchRequests} (${+Math.ceil((t * 100))}%)`, -}, -{ - title: 'Total Produce Requests(秒)', - dataIndex: 'totalProduceRequestsRate', - key: 'totalProduceRequestsRate', - render: (t: number, record: any) => `${record && record.totalProduceRequests} (${+Math.ceil((t * 100))}%)`, -}]; -@observer -export class TopicAnalysis extends React.Component { - public componentDidMount() { - broker.getOneBrokerNetwork(urlQuery.clusterId, urlQuery.brokerId); - broker.getBrokerTopicAnalyzer(urlQuery.clusterId, urlQuery.brokerId); - } - - public render() { - return ( - <> -
-

Broker 状态

- -
-
-

Topic 状态

- 说明:数值后的百分比表示“占Broker总量的百分比” -
; - - - ); - } -} -@observer -class BrokerStatus extends React.Component { - public render() { - return ( -
-
-
- Broker ID -

{urlQuery.brokerId}

-
- {broker.analyzerData ? - Object.keys(brokerMetrics).map((i: keyof IBrokerMetrics) => { - return ( -
- 25 ? 'long-text' : ''}>{brokerMetrics[i]} -

{broker.analyzerData[i] && broker.analyzerData[i].toFixed(2)}

-
- ); - }) : ''} -
-
- ); - } -} diff --git a/console/src/container/broker-detail/topic-info.tsx b/console/src/container/broker-detail/topic-info.tsx deleted file mode 100644 index 8e1dea06..00000000 --- a/console/src/container/broker-detail/topic-info.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import React from 'react'; -import { Table, PaginationConfig } from 'component/antd'; -import { observer } from 'mobx-react'; -import { broker } from 'store/broker'; -import urlQuery from 'store/url-query'; -import moment from 'moment'; -import { ITopic } from 'types/base-type'; -import { SearchAndFilter } from 'container/cluster-topic'; - -const cloumns = [{ - title: 'Topic名称', - key: 'topicName', - width: 350, - onCell: () => ({ - style: { - maxWidth: 250, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - cursor: 'pointer', - }, - }), - sorter: (a: ITopic, b: ITopic) => a.topicName.charCodeAt(0) - b.topicName.charCodeAt(0), - render: (t: string, r: ITopic) => { - return ( - - {r.topicName} - - ); - }, -}, { - title: '分区数', - dataIndex: 'partitionNum', - key: 'partitionNum', - sorter: (a: ITopic, b: ITopic) => b.partitionNum - a.partitionNum, -}, { - title: '副本数', - dataIndex: 'replicaNum', - key: 'replicaNum', - sorter: (a: ITopic, b: ITopic) => b.replicaNum - a.replicaNum, -}, { - title: '流入(KB/s)', - dataIndex: 'byteIn', - key: 'byteIn', - sorter: (a: ITopic, b: ITopic) => b.byteIn - a.byteIn, - render: (t: number) => (t / 1024).toFixed(2), -}, { - title: '流入(QPS)', - dataIndex: 'produceRequest', - key: 'produceRequest', - sorter: (a: ITopic, b: ITopic) => b.produceRequest - a.produceRequest, - render: (t: number) => t.toFixed(2), -}, { - title: '负责人', - dataIndex: 'principals', - key: 'principals', -}, { - title: '修改时间', - dataIndex: 'updateTime', - key: 'updateTime', - sorter: (a: ITopic, b: ITopic) => a.updateTime - b.updateTime, - render: (t: number) => moment(t).format('YYYY-MM-DD HH:mm:ss'), -}, { -}]; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class BrokerTopicInfo extends SearchAndFilter { - public state = { - searchKey: '', - filterClusterVisible: false, - filterStatusVisible: false, - }; - - public componentDidMount() { - broker.getBrokerTopic(urlQuery.clusterId, urlQuery.brokerId); - } - public render() { - const { searchKey } = this.state; - const data: ITopic[] = broker.topics.filter((d) => d.topicName.includes(searchKey) || - (d.principals && d.principals.includes(searchKey))); - return ( - <> -
-
    - {this.renderSearch('请输入Topic名称或者负责人')} -
-
-
- - ); - } -} diff --git a/console/src/container/broker-info/base-info.tsx b/console/src/container/broker-info/base-info.tsx deleted file mode 100644 index df26b25a..00000000 --- a/console/src/container/broker-info/base-info.tsx +++ /dev/null @@ -1,255 +0,0 @@ -import * as React from 'react'; -import './index.less'; -import { Table, Modal, notification, PaginationConfig, Button, Spin } from 'component/antd'; -import { broker, IBroker, IBrokerNetworkInfo, IBrokerPartition } from 'store/broker'; -import { observer } from 'mobx-react'; -import { StatusGraghCom } from 'component/flow-table'; -import urlQuery from 'store/url-query'; -import moment from 'moment'; -import { deleteBroker } from 'lib/api'; -import { SearchAndFilter } from 'container/cluster-topic'; - -import './index.less'; -import { modal } from 'store'; -import { tableFilter } from 'lib/utils'; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 5, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class BrokerStatus extends StatusGraghCom { - public getData() { - return broker.network; - } -} - -@observer -export class BrokerList extends SearchAndFilter { - public state = { - searchKey: '', - searchId: '', - filterRegionVisible: false, - filterStatusVisible: false, - filterVisible: false, - filterRVisible: false, - }; - - public colPartition = (list: IBroker[]) => { - const region = Object.assign({ - title: 'Region', - dataIndex: 'regionName', - key: 'regionName', - filters: tableFilter(list, 'regionName'), - onFilter: (value: string, record: IBroker) => record.regionName === value, - }, this.renderColumnsFilter('filterRVisible')); - - const status = Object.assign({ - title: '已同步', - dataIndex: 'underReplicatedPartitionCount', - key: 'underReplicatedPartitionCount', - filters: [{ text: '是', value: '1' }, { text: '否', value: '0' }], - onFilter: (value: string, record: IBrokerPartition) => { - // underReplicatedPartitionCount > 0 表示未同步完成 - const syncStatus = record.underReplicatedPartitionCount ? '0' : '1'; - return syncStatus === value; - }, - render: (text: number) => ( - <> - {text ? '否' : '是'} - - ), - }, this.renderColumnsFilter('filterVisible')); - - return [{ - title: 'BrokerID', - dataIndex: 'brokerId', - key: 'brokerId', - sorter: (a: IBrokerPartition, b: IBrokerPartition) => a.brokerId - b.brokerId, - }, { - title: '峰值(MB/s)', - dataIndex: 'bytesInPerSec', - key: 'bytesInPerSec', - sorter: (a: IBrokerPartition, b: IBrokerPartition) => a.bytesInPerSec - b.bytesInPerSec, - render: (t: number) => (t / (1024 * 1024)).toFixed(2), - }, { - title: '分区数量', - dataIndex: 'partitionCount', - key: 'partitionCount', - sorter: (a: IBrokerPartition, b: IBrokerPartition) => a.partitionCount - b.partitionCount, - }, { - title: 'Leader数量', - dataIndex: 'leaderCount', - key: 'leaderCount', - sorter: (a: IBrokerPartition, b: IBrokerPartition) => a.leaderCount - b.leaderCount, - }, { - title: '未同步副本数量', - dataIndex: 'notUnderReplicatedPartitionCount', - key: 'notUnderReplicatedPartitionCount', - sorter: (a: IBrokerPartition, b: IBrokerPartition) => - a.notUnderReplicatedPartitionCount - b.notUnderReplicatedPartitionCount, - }, - status, - region, - ]; - } - - public colList = (list: IBroker[]) => { - const region = Object.assign({ - title: 'Region', - dataIndex: 'regionName', - key: 'regionName', - filters: tableFilter(list, 'regionName'), - onFilter: (value: string, record: IBroker) => record.regionName === value, - }, this.renderColumnsFilter('filterRegionVisible')); - - const status = Object.assign({ - title: '状态', - dataIndex: 'status', - key: 'status', - filters: [{ text: '未使用', value: '未使用' }, { text: '使用中', value: '使用中' }], - onFilter: (value: string, record: IBroker) => record.status === value, - render: (t: number) => t ? '未使用' : '使用中', - }, this.renderColumnsFilter('filterStatusVisible')); - - return [{ - title: 'BrokerID', - dataIndex: 'brokerId', - key: 'brokerId', - sorter: (a: IBroker, b: IBroker) => a.brokerId - b.brokerId, - render: (t: string, record: IBroker) => { - return ( - - {t} - - ); - }, - }, { - title: '主机', - dataIndex: 'host', - key: 'host', - sorter: (a: IBroker, b: IBroker) => a.host.charCodeAt(0) - b.host.charCodeAt(0), - }, { - title: 'Port', - dataIndex: 'port', - key: 'port', - sorter: (a: IBroker, b: IBroker) => a.port - b.port, - }, { - title: 'JMX Port', - dataIndex: 'jmxPort', - key: 'jmxPort', - sorter: (a: IBroker, b: IBroker) => a.jmxPort - b.jmxPort, - }, { - title: '启动时间', - dataIndex: 'startTime', - key: 'startTime', - sorter: (a: IBroker, b: IBroker) => a.startTime - b.startTime, - render: (t: number) => moment(t).format('YYYY-MM-DD HH:mm:ss'), - }, { - title: '流入(KB/s)', - dataIndex: 'byteIn', - key: 'byteIn', - sorter: (a: IBroker, b: IBroker) => b.byteIn - a.byteIn, - render: (t: number) => (t / 1024).toFixed(2), - }, { - title: '流出(KB/s)', - dataIndex: 'byteOut', - key: 'byteOut', - sorter: (a: IBroker, b: IBroker) => b.byteOut - a.byteOut, - render: (t: number) => (t / 1024).toFixed(2), - }, - region, - status, - { - title: '操作', - render: (text: string, record: IBroker) => { - return ( - <> - - 详情 - - { } : this.deleteBroker.bind(null, record)} - style={!record.status ? { cursor: 'not-allowed', color: '#999' } : {}} - >删除 - - - - ); - }, - }]; - } - - public deleteBroker = ({ brokerId }: IBroker) => { - Modal.confirm({ - title: `确认删除${brokerId}?`, - okText: '确定', - cancelText: '取消', - onOk: () => { - deleteBroker(urlQuery.clusterId, brokerId).then(() => { - notification.success({ message: '删除成功' }); - broker.getBrokerList(urlQuery.clusterId); - }); - }, - }); - } - - public componentDidMount() { - broker.getBrokerList(urlQuery.clusterId); - broker.getBrokerPartition(urlQuery.clusterId); - } - - public render() { - const dataList = this.state.searchKey !== '' ? - broker.list.filter((d) => d.host.includes(this.state.searchKey) || d.brokerId === +this.state.searchKey) - : broker.list; - const dataPartitions = this.state.searchId !== '' ? - broker.partitions.filter((d) => d.brokerId === +this.state.searchId) : broker.partitions; - return ( - -
-
    -
  • Broker概览
  • -
  • - -
  • - {this.renderSearch('请输入主机或BrokerId')} -
-
-
- - - -
-
    -
  • Broker分区概览
  • -
  • - -
  • - {this.renderSearch('请输入BrokerId', 'searchId')} -
-
- - - ); - } -} diff --git a/console/src/container/broker-info/broker-overview.tsx b/console/src/container/broker-info/broker-overview.tsx deleted file mode 100644 index 1ba42de5..00000000 --- a/console/src/container/broker-info/broker-overview.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import * as React from 'react'; -import { Select, Button, Tooltip } from 'component/antd'; -import { observer } from 'mobx-react'; -import urlQuery from 'store/url-query'; -import './index.less'; -import moment = require('moment'); -import { modal } from 'store'; -import { selecOptions } from './constant'; -import { broker, IBrokerPartition, IOverviewKey } from 'store/broker'; - -@observer -export class BrokerOverview extends React.Component { - public renderSquare = (type: IOverviewKey) => { - return broker.realPartitions.map((item: IBrokerPartition) => { - const brokerDetail = ( -
-

ID:{item.brokerId}

-

{selecOptions[type]}{item[type]}

-

主机: {item.host}

-

端口:{item.port}

-

jmx端口:{item.jmxPort}

-

启动时间:{moment(item.startTime).format('YYYY-MM-DD HH:mm:ss')}

-
- ); - return ( - - {item[type]} - - - ); - }); - } - - public render() { - return ( - <> -
    -
  • - Region - -
  • -
  • - 维度 - -
  • -
  • - -
  • - { - broker.viewType === 'notUnderReplicatedPartitionCount' ? -
  • - - 同步 - - 未同步 -
  • : '' - } -
-
- {this.renderSquare(broker.viewType)} -
- - ); - } -} diff --git a/console/src/container/broker-info/constant.ts b/console/src/container/broker-info/constant.ts deleted file mode 100644 index 1a66c45c..00000000 --- a/console/src/container/broker-info/constant.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const selecOptions = { - partitionCount: '分区数量', - leaderCount: 'leader数量', - notUnderReplicatedPartitionCount: '副本状态', -}; diff --git a/console/src/container/broker-info/index.less b/console/src/container/broker-info/index.less deleted file mode 100644 index 328230fb..00000000 --- a/console/src/container/broker-info/index.less +++ /dev/null @@ -1,84 +0,0 @@ -.square-container { - width: 100%; - background-color: #fff; - padding: 17px 20px; - a { - display: inline-block; - width: 35px; - height: 22px; - background: rgba(255, 241, 240, 1); - border-radius: 4px; - line-height: 22px; - margin-right: 20px; - text-align: center; - color: #f5222d; - &.finished { - background: rgba(47, 194, 91, 0.2); - color: #2fc25b; - } - } -} - -.topic-line-tool { - height: 48px; - font-size: 14px; - font-family: PingFangSC-Regular; - font-weight: 400; - color: rgba(0, 0, 0, 0.85); - background: rgba(250, 250, 250); - li { - display: inline-block; - vertical-align: middle; - margin-left: 24px; - line-height: 48px; - span.label { - padding-right: 10px; - } - &.introduce { - float: right; - span.common { - display: inline-block; - width: 16px; - height: 16px; - border-radius: 8px; - vertical-align: middle; - margin-right: 10px; - &-green { - background: rgba(47, 194, 91, 1); - } - &-red { - background: rgba(245, 34, 45, 1); - } - } - } - } -} - -.k-tab { - width: 100%; - height: 48px; - line-height: 48px; - background: rgba(0, 0, 0, 0.02); - padding: 0px 24px; - font-size: 14px; - font-family: PingFangSC-Medium; - font-weight: 500; - color: rgba(0, 0, 0, 0.85); - display: flex; - justify-content: space-between; - position: relative; - margin: 0; - .k-tab-button { - position: absolute; - right: 213px; - } -} - -.deleteButton { - &.ant-btn { - color: #f38031; - text-decoration: none; - border: none; - background-color: transparent; - } -} diff --git a/console/src/container/broker-info/index.tsx b/console/src/container/broker-info/index.tsx deleted file mode 100644 index f8477379..00000000 --- a/console/src/container/broker-info/index.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import * as React from 'react'; -import { Tabs } from 'component/antd'; -import { BrokerList } from './base-info'; -import { BrokerOverview } from './broker-overview'; - -const TabPane = Tabs.TabPane; - -export class BrokerInfo extends React.Component { - public render() { - return ( - - - - - {/* - - */} - - ); - } -} diff --git a/console/src/container/cluster-topic/index.tsx b/console/src/container/cluster-topic/index.tsx deleted file mode 100644 index cde5193b..00000000 --- a/console/src/container/cluster-topic/index.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import * as React from 'react'; -import { Select, Input, Checkbox, Icon } from 'component/antd'; -import { cluster } from 'store/cluster'; -import { IFiler } from 'types/base-type'; - -const Option = Select.Option; -const Search = Input.Search; - -interface IParams { - filters: IFiler[]; - setSelectedKeys: (selectedKeys: string[]) => void; - confirm?: () => void; -} - -interface IState { - [filter: string]: boolean | string; -} - -export class SearchAndFilter extends React.Component { - public timer: number; - - public renderCluster() { - return ( -
  • - -
  • - ); - } - - public renderSearch(placeholder?: string, keyName: string = 'searchKey') { - return ( -
  • - ); - } - - public onSearchChange = (keyName: string, e: React.ChangeEvent) => { - const searchKey = e.target.value.trim(); - this.setState({ - [keyName]: searchKey, - }); - } - - public handleChange(params: IParams, e: []) { - const { setSelectedKeys, confirm } = params; - setSelectedKeys(e); - confirm(); - } - - public handleVisble = (type: string) => { - if (this.timer) window.clearTimeout(this.timer); - window.setTimeout(() => { - this.setState({ [type]: true }); - }); - } - - public handleUnVisble = (type: string) => { - this.timer = window.setTimeout(() => { - this.setState({ [type]: false }); - }, 100); - } - - public renderFilter = (type: string, params: IParams) => { - const { filters } = params; - return filters !== undefined ? ( -
      - - {filters.map(i =>
    • - {i.text} -
    • )} -
      -
    - ) :
    ; - } - - public renderFilterIcon = (type: string) => { - return ( - - - ); - } - - public renderColumnsFilter = (type: string) => { - return { - filterIcon: this.renderFilterIcon.bind(null, type), - filterDropdownVisible: this.state[type], - filterDropdown: this.renderFilter.bind(null, type), - }; - } -} diff --git a/console/src/container/consumer/index.less b/console/src/container/consumer/index.less deleted file mode 100644 index bec5606f..00000000 --- a/console/src/container/consumer/index.less +++ /dev/null @@ -1,34 +0,0 @@ -.ant-table-title { - padding: 0px 0px 16px 0px; -} - -.consumer-container { - .ant-table-title { - position: absolute; - top: -38px; - } -} - -.group-title { - display: inline-block; - font-size: 14px; - font-weight: 700; - color: rgb(105, 105, 105); - > div { - display: inline-block; - border: 0.5px dashed rgba(0, 0, 0, 0.3); - padding: 5px 8px; - margin-right: 10px; - span { - color: #f38031; - font-weight: 700; - } - &.group-select { - width: 250px; - border: none; - .ant-select { - width: 100%; - } - } - } -} diff --git a/console/src/container/consumer/index.tsx b/console/src/container/consumer/index.tsx deleted file mode 100644 index 54c40454..00000000 --- a/console/src/container/consumer/index.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import * as React from 'react'; - -import { Table, Tabs, PaginationConfig, Select } from 'component/antd'; -import Url from 'lib/url-parser'; -import { topic, IGroupInfo } from 'store/topic'; -import { observer } from 'mobx-react'; -import { TopicDetail } from 'container/topic-detail'; - -import './index.less'; - -const TabPane = Tabs.TabPane; - -const parColumns = [ - { - title: 'Partition ID', - dataIndex: 'partitionId', - key: 'partitionId', - sorter: (a: IGroupInfo, b: IGroupInfo) => a.partitionId - b.partitionId, - }, - { - title: 'Consume ID', - dataIndex: 'clientId', - key: 'clientId', - sorter: (a: IGroupInfo, b: IGroupInfo) => +a.clientId - +b.clientId, - }, - { - title: 'Consumer Offset', - dataIndex: 'consumeOffset', - key: 'consumeOffset', - sorter: (a: IGroupInfo, b: IGroupInfo) => a.consumeOffset - b.consumeOffset, - }, - { - title: 'Partition Offset', - dataIndex: 'partitionOffset', - key: 'partitionOffset', - sorter: (a: IGroupInfo, b: IGroupInfo) => a.partitionOffset - b.partitionOffset, - }, - { - title: 'Lag', - dataIndex: 'lag', - key: 'lag', - sorter: (a: IGroupInfo, b: IGroupInfo) => a.lag - b.lag, - }, -]; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class Consumer extends TopicDetail { - public clusterId: number; - public topicName: string; - public group: string; - public location: string; - - constructor(props: any) { - super(props); - const url = Url(); - this.clusterId = Number(url.search.clusterId); - this.topicName = url.search.topic; - this.location = url.search.location; - this.group = url.search.group; - this.handleGroupChange(this.group + ',' + this.location); - } - - public handleGroupChange = (value: string) => { - const { topicName, clusterId } = this; - topic.getGroupInfo(topicName, clusterId, value.split(',')[0], value.split(',')[1]); - } - - public renderHeader = () => { - return ( -
    - consumerGroup: -
    - -
    -
    - ); - } - - public renderConsumer() { - const data = this.state.searchKey ? - topic.groupInfo.filter((g) => g.partitionId === Number(this.state.searchKey)) : topic.groupInfo; - return ( -
    - ); - } - - public renderTab() { - return ( - - {this.renderConsumer()} - - ); - } -} diff --git a/console/src/container/drawer/index.less b/console/src/container/drawer/index.less deleted file mode 100644 index d3da1937..00000000 --- a/console/src/container/drawer/index.less +++ /dev/null @@ -1,31 +0,0 @@ -.o-container { - width: 100%; - padding: 40px 0 0 10px; - .b-list { - button { - margin: 0 5px 0 10px; - } - } - .headLine { - padding-top: 30px; - margin-top: 30px; - color: #f38031; - border-top: 1px solid rgb(216, 216, 216); - } - .timeButton { - position: relative; - left: 260px; - top: 40px; - } - .partionButton { - float: right; - margin: 20px 15px 0 0; - } - .b-item { - margin-top: 20px; - padding-left: 222px; - button { - margin-right: 10px; - } - } -} diff --git a/console/src/container/drawer/index.tsx b/console/src/container/drawer/index.tsx deleted file mode 100644 index 21d3a4ec..00000000 --- a/console/src/container/drawer/index.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; -import { drawer } from 'store/drawer'; - -import ResetOffset from './reset-offset'; -import TopicSample from './topic-sample'; - -@observer -export default class AllDrawerInOne extends React.Component { - public render() { - if (!drawer.id) return null; - return ( - <> - {drawer.id === 'showResetOffset' ? : null} - {drawer.id === 'showTopicSample' ? : null} - - ); - } -} diff --git a/console/src/container/drawer/reset-offset.tsx b/console/src/container/drawer/reset-offset.tsx deleted file mode 100644 index f9690045..00000000 --- a/console/src/container/drawer/reset-offset.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import * as React from 'react'; -import { Drawer, Form, Row, Button, Input, DatePicker, Col, Select, message, Alert } from 'component/antd'; -import { drawer } from 'store/drawer'; -import { topic } from 'store/topic'; -import { consume } from 'store/consume'; -import { observer } from 'mobx-react'; - -import './index.less'; -import moment = require('moment'); - -@observer -class ResetOffset extends React.Component { - - public handleSubmit = (e: React.MouseEvent) => { - e.preventDefault(); - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - const { timestamp } = values; - consume.offsetPartition(Object.assign({ timestamp: +moment(timestamp).format('x') }, topic.currentGroup)) - .then(() => { - message.success('重置时间成功'); - window.setTimeout(() => { - location.reload(); - }, 200); - }); - }); - } - public submitPartiton = () => { - consume.offsetPartition(topic.currentGroup, 1).then(() => { - message.success('重置分区成功'); - window.setTimeout(() => { - location.reload(); - }, 200); - }); - } - - public render() { - const { getFieldDecorator } = this.props.form; - return ( - - -
    -
    - -

    重置到指定时间

    -
    - -
    - - {getFieldDecorator('timestamp', { - rules: [{ required: true, message: '请选择时间' }], - initialValue: moment(), - })( - , - )} - - - - - - - - - -

    重置到指定分区

    -
    - - - -
    partitionId - partitionOffset - - {consume.offsetList.map((ele, index) => { - return ( - - - - - - - - - - - - - - - ); - } -} - -export default Form.create({ name: 'topicSample' })(ResetOffset); diff --git a/console/src/container/drawer/topic-sample.tsx b/console/src/container/drawer/topic-sample.tsx deleted file mode 100644 index c69c8e3a..00000000 --- a/console/src/container/drawer/topic-sample.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import * as React from 'react'; -import { Drawer, Form, Row, Button, Input, InputNumber, notification } from 'component/antd'; -import { drawer } from 'store/drawer'; - -import './index.less'; -import { topic } from 'store/topic'; - -const topicFormItemLayout = { - labelCol: { - span: 5, - }, - wrapperCol: { - span: 14, - }, -}; - -class TopicSample extends React.Component { - public state = { - loading: false, - }; - - public handleSubmit = (e: React.MouseEvent) => { - e.preventDefault(); - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - const { offset, partitionId } = values; - const bothExist = [offset, partitionId].filter(item => item === undefined || item === null).length; - if (bothExist === 1) { - notification.error({ message: '分区号和偏移量必须同时存在' }); - return false; - } - this.setState({ loading: true }); - topic.addSample(Object.assign(drawer.topicData, values)).then(() => this.setState({ loading: false })); - }); - } - - public cleanData = () => { - topic.sampleData = null; - drawer.close(); - } - public render() { - const { getFieldDecorator } = this.props.form; - return ( - -
    -
    - - - {getFieldDecorator('maxMsgNum', { - rules: [{ required: true, message: '请输入最大采样条数' }], - initialValue: 1, - })()} - - - - - {getFieldDecorator('timeout', { - rules: [{ required: true, message: '请输入最大采样时间' }], - initialValue: 3000, - })()} - - - - - {getFieldDecorator('partitionId')()} - - - - - {getFieldDecorator('offset')()} - - - - - - - - - - { - topic.sampleData ? - topic.sampleData.map((i: any, index: number) => { - return ; - }) : null - } -
    -
    - ); - } -} - -export default Form.create({ name: 'topicSample' })(TopicSample); diff --git a/console/src/container/header/index.less b/console/src/container/header/index.less deleted file mode 100644 index c0aec734..00000000 --- a/console/src/container/header/index.less +++ /dev/null @@ -1,103 +0,0 @@ -.kafka-header-container { - height: 64px; - background-color: #fff; - box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, .1); - position: relative; - z-index: 100; - display: flex; - flex-flow: row nowrap; - .left-content { - width: 220px; - margin-left: 16px; - } - .mid-content { - flex: 1; - padding-left: 100px; - a { - color: #4A4A4A; - &:hover { - color: #f38031; - } - } - span { - display: inline-block; - vertical-align: middle; - position: relative; - line-height: 64px; - width: 120px; - text-align: center; - &.k-active { - a { - color: #f38031; - } - &:after { - width: 100%; - content: ''; - height: 4px; - position: absolute; - bottom: 0; - left: 0; - background: #f38031; - } - } - } - } - .right-content { - margin-right: 24px; - position: relative; - .kafka-avatar-icon { - font-size: 24px; - position: absolute; - top: 15px; - left: -30px; - width: 32px; - height: 32px; - } - .kafka-header-text { - font-size: 14px; - } - } - .left-content, - .right-content { - font-size: 0; - & > span { - display: inline-block; - line-height: 64px; - vertical-align: middle; - } - } - - .kafka-header-icon { - height: 45px; - width: 45px; - img { - width: 100%; - height: 100%; - } - } - .kafka-header-text { - margin-left: 16px; - font-size: 18px; - font-weight: 500; - font-family: PingFangSC-Medium; - color: rgba(25,24,24,1); - cursor: pointer; - } -} -.kafka-header-menu { - width: 88px; - background-color: #fff; - position: absolute; - top: -20px; - box-shadow: 0px 0px 4px 0px rgba(217,217,217); - border-radius: 4px; - li { - text-align: center; - height: 32px; - line-height: 32px; - cursor: pointer; - &:hover { - background: rgba(236,111,38,0.1); - } - } -} \ No newline at end of file diff --git a/console/src/container/header/index.tsx b/console/src/container/header/index.tsx deleted file mode 100644 index dfb6a419..00000000 --- a/console/src/container/header/index.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import * as React from 'react'; - -import './index.less'; -import { getCookie, deleteCookie } from 'lib/utils'; -import { userLogoff } from 'lib/api'; -import { notification, Dropdown } from 'component/antd'; -import { users } from 'store/users'; -import logoUrl from '../../assets/image/kafka-logo.png'; -import devIcon from '../../assets/image/devops.png'; -import adminIcon from '../../assets/image/admin.png'; -import userIcon from '../../assets/image/normal.png'; - -interface IHeader { - active: string; -} - -export const Header = (props: IHeader) => { - const { active } = props; - const username = getCookie('username'); - const role = Number(getCookie('role')); - - const logoff = () => { - userLogoff(username).then(() => { - notification.success({ message: '退出成功' }); - deleteCookie(['username', 'role']); - location.reload(); - }); - }; - - const menu = ( -
      - {role ?
    • 管理
    • : ''} -
    • 退出
    • -
    - ); - - return ( -
    -
    - - Kafka Manager -
    -
    - 集群监控 - {role ? 集群管控 : ''} -
    -
    - - - - {users.mapRole(role)} : {username} - -
    -
    - ); -}; diff --git a/console/src/container/left-menu/constant.ts b/console/src/container/left-menu/constant.ts deleted file mode 100644 index 054e8389..00000000 --- a/console/src/container/left-menu/constant.ts +++ /dev/null @@ -1,79 +0,0 @@ -export const userMenu = [{ - href: '/', - i: 'k-icon-iconfontzhizuobiaozhun023110', - title: 'Topic列表', -}, { - href: '/user/my_order', - i: 'k-icon-order1', - title: '工单列表', -}, { - href: '/user/alarm', - i: 'k-icon-gaojing', - title: '告警配置', -}, { - href: '/user/modify_user', - i: 'k-icon-yonghuguanli', - title: '密码修改', -}]; - -export const adminMenu = [{ - href: '/admin', - i: 'k-icon-jiqun', - title: '集群列表', -}, { - href: '/admin/order', - i: 'k-icon-order1', - title: '资源审批', -}, -// }, { -// href: '/admin/task', -// i: 'k-icon-renwuliebiao', -// title: '任务列表', -// }, { -// { -// href: '/admin/alarm', -// i: 'k-icon-gaojing', -// title: '告警配置', -// }, { -{ - href: '/admin/user_manage', - i: 'k-icon-yonghuguanli', - title: '用户管理', -}, -// }, { -// href: '/admin/auto_approval', -// i: 'k-icon-shenpi1', -// title: '自动审批管理', -// }, { -{ - href: '/admin/operation', - i: 'k-icon-xiaofeikecheng', - title: '任务管理', -// }, { -// href: '/admin/modify_user', -// i: 'k-icon-jiaoseshouquan', -// title: '密码修改', -}]; - -export interface IMenuItem { - href: string; - i: string; - title: string; -} - -export const userMap = new Map(); -userMenu.forEach(m => { - userMap.set(m.href, m); -}); - -export const adminMap = new Map(); -adminMenu.forEach(m => { - adminMap.set(m.href, m); -}); - -export const getActiveMenu = (mode: 'admin' | 'user', href: string) => { - const map = mode === 'admin' ? adminMap : userMap; - const defaultMenu = mode === 'admin' ? '/admin' : '/'; - const menuItem = map.get(href); - return menuItem && menuItem.href || defaultMenu; -}; diff --git a/console/src/container/left-menu/index.tsx b/console/src/container/left-menu/index.tsx deleted file mode 100644 index 4c142e44..00000000 --- a/console/src/container/left-menu/index.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from 'react'; - -import './index.less'; -import { Tooltip, Icon } from 'component/antd'; -import { adminMenu, userMenu } from './constant'; -import { BrowserRouter as Router, NavLink } from 'react-router-dom'; - -interface ILeftMenuProps { - page: string; - mode?: 'admin' | 'user'; -} - -export class LeftMenu extends React.Component { - public state = { - status: 'k-open', - }; - - public open = () => { - const { status } = this.state; - const newStatus = !status ? 'k-open' : ''; - this.setState({ - status: newStatus, - }); - } - - public render() { - const { status } = this.state; - const { page, mode } = this.props; - const menu = mode === 'admin' ? adminMenu : userMenu; - return ( -
    -
      - { - menu.map((m, i) => { - const cnt = ( -
    • - - - {status ? {m.title} : null} - -
    • - ); - - if (!status) { - return {cnt}; - } - return cnt; - }) - } -
    -
    - -
    -
    - ); - } -} diff --git a/console/src/container/modal/admin-expand.tsx b/console/src/container/modal/admin-expand.tsx deleted file mode 100644 index 6925e854..00000000 --- a/console/src/container/modal/admin-expand.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Input, Select, notification } from 'component/antd'; -import { modal } from 'store/modal'; -import { cluster } from 'store/cluster'; -import { operation } from 'store/operation'; -import { topic, IAdminExpand } from 'store/topic'; -import { observer } from 'mobx-react'; -import { broker } from 'store/broker'; -import { topicDilatation } from 'lib/api'; -import urlQuery from 'store/url-query'; -import { IValueLabel } from 'types/base-type'; - -const topicFormItemLayout = { - labelCol: { - span: 7, - }, - wrapperCol: { - span: 11, - }, -}; -@observer -class Topic extends React.Component { - - public handleSubmit = () => { - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - values.partitionNum = +values.partitionNum; - topicDilatation(values).then(() => { - topic.getAdminTopics(urlQuery.clusterId); - notification.success({ message: '扩容成功' }); - modal.close(); - }); - }); - } - - public componentDidMount() { - const { clusterId, topicName } = modal.topicDetail; - operation.initRegionOptions(clusterId); - broker.initBrokerOptions(clusterId); - cluster.getClusters(); - topic.getTopicMetaData(clusterId, topicName); - } - - public render() { - const { getFieldDecorator } = this.props.form; - const initialData = topic.topicDetail || {} as IAdminExpand; - return ( - -
    - - - {getFieldDecorator('clusterId', { - rules: [{ required: true, message: '请选择集群' }], - initialValue: +initialData.clusterId || +cluster.data[1].clusterId, - })( - , - )} - - - - - {getFieldDecorator('topicName', { - rules: [{ required: true, message: '请选择Topic' }], - initialValue: initialData.topicName, - })( - , - )} - - - - - - - - - - - - - {getFieldDecorator('brokerIdList', { - initialValue: initialData.brokerIdList || [], - rules: [{ - required: true, - validator: (_: any, value: string, callback: (wrong?: string) => void) => { - if (initialData.replicaNum > value.length) { - callback('Broker数需要大于或等于副本数'); - } - callback(); - }, - }], - })( - , - )} - - - {getFieldDecorator('partitionNum', { - rules: [{ required: true, message: '请输入新增分区数' }], - })( - , - )} - - -
    - ); - } -} - -export default Form.create({ name: 'topic' })(Topic); diff --git a/console/src/container/modal/alarm-config.tsx b/console/src/container/modal/alarm-config.tsx deleted file mode 100644 index 611dff41..00000000 --- a/console/src/container/modal/alarm-config.tsx +++ /dev/null @@ -1,303 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Input, Select, notification, Col, Radio } from 'component/antd'; -import { modal } from 'store/modal'; -import { alarm } from 'store/alarm'; -import { observer } from 'mobx-react'; -import { cluster } from 'store/cluster'; -import { addAlarm, modifyAlarm } from 'lib/api'; -import { topic } from 'store/topic'; -import { broker } from 'store/broker'; -import { getRandomPassword, getCookie } from 'lib/utils'; -import { IAlarmBase } from 'types/base-type'; - -const Option = Select.Option; - -const topicFormItemLayout = { - labelCol: { - span: 6, - }, - wrapperCol: { - span: 14, - }, -}; - -@observer -class Alarm extends React.Component { - public data: any = null; - public state = { - loading: false, - type: 'Lag', - }; - - public handleSubmit = () => { - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - this.setState({ loading: true }); - const { metric, opt, threshold, duration, alarmName, principalList: principal, actionTag, status } = values; - const principalList = typeof (principal) === 'object' ? principal : principal.split(','); - const strategyActionList = [{ actionTag, actionWay: 'KAFKA' }]; - const strategyFilterList = Array.from(['topicName', 'consumerGroup', 'brokerId', 'clusterId'], (item) => { - if ((this.state.type === 'Lag' || !+getCookie('role')) && item === 'brokerId') return; - if (this.state.type !== 'Lag' && item === 'consumerGroup' || JSON.stringify(values[item]) === '[]') return; - return { - key: item, - value: values[item], - }; - }).filter(i => i); - const params: IAlarmBase = { - status, strategyActionList, strategyFilterList, alarmName, principalList, - strategyExpressionList: [{ metric, opt, threshold: +threshold, duration: +duration }], - }; - const notiMessage = alarm.curData ? { message: '修改成功' } : { message: '添加告警成功' }; - const fn = alarm.curData ? modifyAlarm : addAlarm; - fn(alarm.curData ? Object.assign({ id: alarm.curData.id }, params) : params).then(() => { - notification.success(notiMessage); - alarm.getAlarm(); - modal.close(); - }, (err) => { - this.setState({ loading: false }); - }); - }); - } - - public initSelection = (value: number) => { - topic.getTopicList(value); - broker.initBrokerOptions(value); - } - - public componentDidMount = () => { - cluster.getClusters(); - if (this.isModify()) { - this.setState({ type: alarm.curData.strategyExpressionList[0].metric }, () => { - this.data = this.getFilterList(); - }); - } - } - - public onChange = (type: any) => { - this.setState({ type }); - } - - public filterSelection = (input: string, option: any) => { - return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0; - } - - public getFilterList = () => { - const filterList = new Map(); - alarm.curData.strategyFilterList.forEach(item => { - filterList.set(item.key, item.value); - }); - this.initSelection(+filterList.get('clusterId')); - return filterList; - } - - public getActionTag = () => { - this.props.form.setFieldsValue({ - actionTag: 'KAFKA_' + getRandomPassword(), - }); - } - - public isModify = () => !!alarm.curData; - - public render() { - const { getFieldDecorator } = this.props.form; - const { loading, type } = this.state; - const isModify = this.isModify(); - const initialData = alarm.curData; - const { data } = this; - const role = +getCookie('role'); - return ( - -
    - - {getFieldDecorator('alarmName', { - rules: [{ required: true, message: '告警规则名称' }], - initialValue: isModify ? initialData.alarmName : '', - })( - , - )} - - - {getFieldDecorator('principalList', { - rules: [{ required: true, message: '请输入负责人' }], - initialValue: isModify ? initialData.principalList : getCookie('username'), - })( - , - )} - - -
    -

    告警规则:

    - -
    - - - - {getFieldDecorator('metric', { - rules: [{ required: true, message: '请选择 Metric' }], - initialValue: isModify ? initialData.strategyExpressionList[0].metric : '', - })( - , - )} - - - - - {getFieldDecorator('opt', { - rules: [{ required: true, message: '请选择 Condition' }], - initialValue: isModify ? initialData.strategyExpressionList[0].opt : '', - })( - , - )} - - - - - - - {getFieldDecorator('threshold', { - rules: [{ required: true, message: '请输入 value' }], - initialValue: isModify ? initialData.strategyExpressionList[0].threshold : '', - })( - , - )} - - - - - {getFieldDecorator('duration', { - rules: [{ required: true, message: '请输入持续时间' }], - initialValue: isModify ? initialData.strategyExpressionList[0].duration : '', - })( - , - )} - - - - - - - -

    过滤规则:

    - -
    - 集群名称 - - {getFieldDecorator('clusterId', { - rules: [{ required: true, message: '请选择集群' }], - initialValue: data && +data.get('clusterId') || '', - })( - , - )} - - - Topic名称 - - {getFieldDecorator('topicName', { - rules: [{ required: type === 'Lag' || !role, message: '请选择Topic' }], - initialValue: data && data.get('topicName') || '', - })( - , - )} - - - {type !== 'Lag' ? role ? ( - - BrokeId - - {getFieldDecorator('brokerId', { - initialValue: data && data.get('brokerId') || [], - })( - , - )} - - - ) : null : ( - <> - 消费组 - - {getFieldDecorator('consumerGroup', { - rules: [{ required: type === 'Lag', message: '请输入消费组' }], - initialValue: data && data.get('consumerGroup') || '', - })( - , - )} - - - )} - - - - {getFieldDecorator('actionTag', { - rules: [{ required: true, message: '请输入tag' }], - initialValue: isModify ? initialData.strategyActionList[0].actionTag : '', - })( - 自动生成} />, - )} - - - {getFieldDecorator('status', { - initialValue: isModify ? initialData.status : 1, - })( - - - - , - )} - - - - ); - } -} - -export default Form.create({ name: 'alarm' })(Alarm); diff --git a/console/src/container/modal/cluster-network.tsx b/console/src/container/modal/cluster-network.tsx deleted file mode 100644 index 610205ec..00000000 --- a/console/src/container/modal/cluster-network.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import * as React from 'react'; -import { Modal } from 'component/antd'; -import { modal } from 'store/modal'; -import { NetWorkFlow } from 'container/topic-detail/com'; - -export class ClusterDetail extends React.Component { - public render() { - return ( - -
    - -
    -
    - ); - } -} diff --git a/console/src/container/modal/cluster.tsx b/console/src/container/modal/cluster.tsx deleted file mode 100644 index 6a96445c..00000000 --- a/console/src/container/modal/cluster.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Input, Select, Radio, message } from 'component/antd'; -import { modal } from 'store/modal'; -import { cluster } from 'store/cluster'; -import { INewCluster } from 'types/base-type'; -import { newCluster, modifyCluster } from 'lib/api'; - -const Option = Select.Option; - -const topicFormItemLayout = { - labelCol: { - span: 8, - }, - wrapperCol: { - span: 12, - }, -}; - -class Cluster extends React.Component { - public handleSubmit = (e: React.MouseEvent) => { - e.preventDefault(); - const { clusterId } = modal.currentCluster; - this.props.form.validateFieldsAndScroll((err: any, values: INewCluster) => { - if (err) return; - const commonFn = (fn: any) => { - fn.then(() => { - message.success(this.getTips()); - modal.close(); - cluster.getClusters(); - }); - }; - clusterId ? - commonFn(modifyCluster(Object.assign(values, {clusterId}))) : commonFn(newCluster(values)); - }); -} - - public getTips() { - if (modal.currentCluster.clusterId) return '修改成功'; - return '添加成功'; - } - - public getTitle() { - if (modal.currentCluster.clusterId) return '修改集群'; - return '添加集群'; - } - - public render() { - const { getFieldDecorator } = this.props.form; - return ( - -
    - - - {getFieldDecorator('clusterName', { - rules: [{ required: true, message: '请输入集群名称' }], - initialValue: modal.currentCluster.clusterName, - })( - , - )} - - - - - {getFieldDecorator('zookeeper', { - rules: [{ required: true, message: '请输入 zookeeper 地址' }], - initialValue: modal.currentCluster.zookeeper, - })( - , - )} - - - - - {getFieldDecorator('kafkaVersion', { - rules: [{ required: true, message: '请选择 kafka 版本' }], - initialValue: modal.currentCluster.kafkaVersion, - })( - , - )} - - - - - {getFieldDecorator('bootstrapServers', { - rules: [{ required: true, message: '请输入集群访问地址' }], - initialValue: modal.currentCluster.bootstrapServers, - })( - , - )} - - - - - {getFieldDecorator('saslJaasConfig', { - initialValue: modal.currentCluster.saslJaasConfig, - })( - , - )} - - - - - {getFieldDecorator('saslMechanism', { - initialValue: modal.currentCluster.saslMechanism, - })( - , - )} - - - - - {getFieldDecorator('securityProtocol', { - initialValue: modal.currentCluster.securityProtocol, - })( - , - )} - - - - - {getFieldDecorator('alarmFlag', { - rules: [{ required: true, message: '请选择是否开启告警' }], - initialValue: modal.currentCluster.alarmFlag === undefined ? 1 : modal.currentCluster.alarmFlag, - })( - - - - , - )} - - - -
    - ); - } -} - -export default Form.create({ name: 'cluster' })(Cluster); diff --git a/console/src/container/modal/cosumer-topic.tsx b/console/src/container/modal/cosumer-topic.tsx deleted file mode 100644 index 6d2ccf5a..00000000 --- a/console/src/container/modal/cosumer-topic.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import * as React from 'react'; -import { modal } from 'store/modal'; -import { consume } from 'store/consume'; -import Modal from 'antd/es/modal'; -import { observer } from 'mobx-react'; -import Table from 'antd/es/table'; - -const columns = [ - { - title: 'Topic 列表', - dataIndex: 'topicName', - key: 'topicName', - }, -]; - -@observer -export default class ConsumerTopic extends React.Component { - public componentDidMount() { - const { clusterId, consumerGroup, location } = modal.consumberGroup; - consume.getConsumerTopic(clusterId, consumerGroup, location.toLowerCase()); - } - public render() { - return ( - -
    - - ); - } -} diff --git a/console/src/container/modal/index.tsx b/console/src/container/modal/index.tsx deleted file mode 100644 index 647d07d0..00000000 --- a/console/src/container/modal/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; -import { modal } from 'store/modal'; -import TopicNew from './topic-new'; -import TopicExpand from './topic-expand'; -import Alarm from './alarm-config'; -import ClusterNew from './cluster'; -import LeaderRebalance from './leader-rebalance'; -import Task from './task-new'; -import OrderApprove from './order-approve'; -import PartitionApprove from './partition-approve'; -import NewUser from './new-user'; -import Region from './region'; -import TopicCreate from './topic-create'; -import AdminExpand from './admin-expand'; -import ConsumerTopic from './cosumer-topic'; - -import './index.less'; - -@observer -export default class AllModalInOne extends React.Component { - public render() { - if (!modal.id) return null; - return ( - <> - {modal.id === 'showNewTopic' ? : null} - {modal.id === 'showNewCluster' ? : null} - {modal.id === 'showModifyCluster' ? : null} - {modal.id === 'showAdimTopic' ? : null} - {modal.id === 'showExpandTopic' ? : null} - {modal.id === 'showExpandAdmin' ? : null} - {modal.id === 'showAlarm' ? : null} - {modal.id === 'showAlarmModify' ? : null} - {modal.id === 'showRegion' ? : null} - {modal.id === 'showLeaderRebalance' ? : null} - {modal.id === 'showTask' ? : null} - {modal.id === 'showTaskDetail' ? : null} - {modal.id === 'showOrderApprove' ? : null} - {modal.id === 'showOrderDetail' ? : null} - {modal.id === 'showPartitionDetail' ? : null} - {modal.id === 'showPartition' ? : null} - {modal.id === 'showNewUser' ? : null} - {modal.id === 'showConsumerTopic' ? : null} - - ); - } -} diff --git a/console/src/container/modal/leader-rebalance.tsx b/console/src/container/modal/leader-rebalance.tsx deleted file mode 100644 index 57d4ff7d..00000000 --- a/console/src/container/modal/leader-rebalance.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Input, Button, Table } from 'component/antd'; -import { modal } from 'store/modal'; -import Url from 'lib/url-parser'; -import { cluster } from 'store/cluster'; -import { addRebalance } from 'lib/api'; -import { observer } from 'mobx-react'; - -const topicFormItemLayout = { - labelCol: { - span: 5, - }, - wrapperCol: { - span: 16, - }, -}; - -const columns = [ - { - title: '集群', - dataIndex: 'clusterName', - key: 'clusterName', - }, - { - title: 'Broker ID', - dataIndex: 'brokerId', - key: 'brokerId', - }, - { - title: 'Status', - dataIndex: 'status', - key: 'status', - }, -]; - -@observer -class LeaderRebalance extends React.Component { - public clusterName: string; - public clusterId: number; - public brokerId: number; - - public state = { - loading: false, - }; - constructor(props: any) { - super(props); - const url = Url(); - if (url.search.clusterName) { - this.clusterName = decodeURI(url.search.clusterName); - } - this.clusterId = Number(url.search.clusterId); - } - - public handleSubmit = (e: React.MouseEvent) => { - e.preventDefault(); - this.props.form.validateFieldsAndScroll((err: any, values: any) => { - if (err) { - return; - } - this.setState({ loading: true }); - this.brokerId = Number(values.brokerId); - addRebalance({ brokerId: this.brokerId, clusterId: this.clusterId, dimension: 0 }).then(() => { - cluster.getRebalance(this.clusterId).then(() => { - if (cluster.leaderStatus && cluster.leaderStatus !== 'RUNNING') { - this.setState({ loading: false }); - } - }); - }); - }); - } - - public render() { - const { getFieldDecorator } = this.props.form; - const { brokerId, clusterName } = this; - return ( - -
    - - - - - {getFieldDecorator('brokerId', { - rules: [{ required: true, message: 'brokerId 不能为空' }], - })()} - - - - - - { - cluster.leaderStatus ?
    : '' - } - - ); - } -} - -export default Form.create({ name: 'LeaderRebalance' })(LeaderRebalance); diff --git a/console/src/container/modal/new-user.tsx b/console/src/container/modal/new-user.tsx deleted file mode 100644 index 775af0e8..00000000 --- a/console/src/container/modal/new-user.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Input, notification, Select } from 'component/antd'; -import { modal } from 'store/modal'; -import { users } from 'store/users'; -import { addUser, modifyUser } from 'lib/api'; -import { getRandomPassword } from 'lib/utils'; -import { IUserDetail } from 'store/users'; - -import './index.less'; - -const topicFormItemLayout = { - labelCol: { - span: 7, - }, - wrapperCol: { - span: 11, - }, -}; - -class NewUser extends React.Component { - - public handleSubmit = () => { - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - this.getIsModify() ? - modifyUser(values).then(() => { - notification.success({ message: '修改成功' }); - modal.close(); - users.getUsers(); - }) : - addUser(values).then(() => { - notification.success({ message: '创建用户成功' }); - modal.close(); - users.getUsers(); - }); - }); - } - - public getPassword = () => { - this.props.form.setFieldsValue({ - password: getRandomPassword(6), - }); - } - - public getIsModify = () => !!modal.userDetail; - - public render() { - const { getFieldDecorator } = this.props.form; - const initailData = modal.userDetail || {} as IUserDetail; - const isModify = this.getIsModify(); - return ( - -
    - - - {getFieldDecorator('username', { - rules: [{ required: true, message: '请输入用户名' }], - initialValue: initailData.username, - })( - , - )} - - - - - {getFieldDecorator('password', { - rules: [ - { required: !isModify, message: '请输入密码' }, - { pattern: /^[a-zA-Z0-9]{6,10}$/, message: '请输入6-10位密码' }], - nitialValue: initailData.password, - })( - 随机生成密码} - placeholder="请输入密码" - />, - )} - - - - - {getFieldDecorator('role', { - rules: [{ required: true, message: '请选择角色' }], - initialValue: initailData.role, - })( - , - )} - - - -
    - ); - } -} - -export default Form.create({ name: 'newUser' })(NewUser); diff --git a/console/src/container/modal/order-approve.tsx b/console/src/container/modal/order-approve.tsx deleted file mode 100644 index 2bb112c6..00000000 --- a/console/src/container/modal/order-approve.tsx +++ /dev/null @@ -1,250 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Col, Input, Select, Button, notification, Collapse, Switch } from 'component/antd'; -import { modal } from 'store/modal'; -import { addTopicApprove } from 'lib/api'; -import { region } from 'store/region'; -import './index.less'; -import { broker } from 'store/broker'; -import moment from 'moment'; -import { observer } from 'mobx-react'; -import { order } from 'store/order'; -import { IValueLabel } from 'types/base-type'; - -const topicFormItemLayout = { - labelCol: { - span: 7, - }, - wrapperCol: { - span: 16, - }, -}; - -@observer -class OrderApprove extends React.Component { - public state = { - broker: false, - orderStatus: 1, - }; - - public handleSubmit = (e: React.MouseEvent) => { - e.preventDefault(); - if (modal.id === 'showOrderDetail') { modal.close(); return false; } - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - const { orderStatus } = this.state; - const { orderId } = modal.orderDetail; - const params = Object.assign(values, { orderStatus, orderId }); - addTopicApprove(params).then(() => { - notification.success({ message: '审批成功' }); - order.getAdminOrder(); - modal.close(); - }); - }); - } - - public handleReject = (e: React.MouseEvent) => { - const event = e.currentTarget; - this.setState({orderStatus: 2}, () => { - event.nextElementSibling.click(); - }); - } - - public changeBroker = (broker: boolean) => { - this.setState({ broker }); - } - - public componentDidMount = () => { - region.getRegions(modal.orderDetail.clusterId); - broker.initBrokerOptions(modal.orderDetail.clusterId); - } - - public renderFooter = () => { - return ( - - { - modal.id !== 'showOrderDetail' ? - <> - - - - : null - } - - ); - } - - public render() { - const { orderDetail } = modal; - const disabled = modal.id === 'showOrderDetail'; - const { getFieldDecorator } = this.props.form; - const { orderStatus } = this.state; - return ( - - - -
    - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -
    - - - - - - - - { - this.state.broker ? - - {getFieldDecorator('regionIdList', { - rules: [{ required: orderStatus === 1, message: '不能为空' }], - })( - , - )} - - : - - {getFieldDecorator('brokerIdList', { - rules: [{ required: orderStatus === 1, message: '不能为空' }], - initialValue: (orderDetail.brokers && orderDetail.brokers.split(',')) || - (orderDetail.regions && orderDetail.regions.split(',')) || [], - })( - , - )} - - } - - - - {getFieldDecorator('replicaNum', { - rules: [{ required: orderStatus === 1, message: '不能为空' }], - initialValue: orderDetail.replicaNum || '', - })()} - - - - - - - {getFieldDecorator('retentionTime', { - rules: [{ required: orderStatus === 1, message: '不能为空' }], - initialValue: orderDetail && orderDetail.retentionTime / 3600000 || '', - })()} - - - - - {getFieldDecorator('partitionNum', { - rules: [{ required: orderStatus === 1, message: '不能为空' }], - initialValue: orderDetail.partitionNum, - })()} - - - - - - - {getFieldDecorator('approvalOpinions', { - rules: [{ required: orderStatus === 2, message: '审批意见不能为空' }], - initialValue: orderDetail.approvalOpinions || undefined, - })()} - - - - - - - - ); - } -} - -export default Form.create({ name: 'orderApprove' })(OrderApprove); diff --git a/console/src/container/modal/partition-approve.tsx b/console/src/container/modal/partition-approve.tsx deleted file mode 100644 index 40efe441..00000000 --- a/console/src/container/modal/partition-approve.tsx +++ /dev/null @@ -1,209 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Col, Input, Select, Button, notification, Switch } from 'component/antd'; -import { modal } from 'store/modal'; -import { addAdminPartition } from 'lib/api'; -import { broker } from 'store/broker'; -import { observer } from 'mobx-react'; -import moment from 'moment'; -import { getCookie } from 'lib/utils'; -import { order } from 'store/order'; -import { IValueLabel } from 'types/base-type'; -import './index.less'; - -const topicFormItemLayout = { - labelCol: { - span: 8, - }, - wrapperCol: { - span: 14, - }, -}; - -@observer -class PartitionApprove extends React.Component { - public state = { - orderStatus: 1, - }; - public componentDidMount() { - const { clusterId } = modal.orderDetail; - broker.initBrokerOptions(clusterId); - } - - public handleSubmit = (e: React.MouseEvent) => { - e.preventDefault(); - if (modal.id === 'showPartitionDetail') { modal.close(); return false; } - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - const { orderStatus } = this.state; - const { orderId } = modal.orderDetail; - const { partitionNum: num } = values; - values.partitionNum = +num; - const params = Object.assign(values, { orderStatus, orderId }); - addAdminPartition(params).then(() => { - notification.success({ message: '审批成功' }); - order.getAdminOrder(); - modal.close(); - }); - }); - } - - public handleReject = (e: React.MouseEvent) => { - const event = e.currentTarget; - this.setState({ orderStatus: 2 }, () => { - event.nextElementSibling.click(); - }); - } - - public renderFooter = () => { - return ( - - { - modal.id !== 'showPartitionDetail' ? - <> - - - - : null - } - - ); - } - - public render() { - const { orderDetail } = modal; - const disabled = modal.id === 'showPartitionDetail'; - const { getFieldDecorator } = this.props.form; - const { orderStatus } = this.state; - return ( - -
    - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {getFieldDecorator('partitionNum', { - rules: [{ required: orderStatus === 1, message: '不能为空' }], - })()} - - - - - - {getFieldDecorator('brokerIdList', { - rules: [{ required: orderStatus === 1, message: '不能为空' }], - initialValue: orderDetail.brokerIdList || [], - })( - , - )} - - - - - - {getFieldDecorator('approvalOpinions', { - rules: [{ required: orderStatus === 2, message: '审批意见不能为空' }], - initialValue: orderDetail.approvalOpinions || undefined, - })()} - - - - - - ); - } -} - -export default Form.create({ name: 'partitionApprove' })(PartitionApprove); diff --git a/console/src/container/modal/region.tsx b/console/src/container/modal/region.tsx deleted file mode 100644 index 9a124cc0..00000000 --- a/console/src/container/modal/region.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import { Modal, Form, Row, Select, Input, message } from 'component/antd'; -import { IRegionData, statusMap, region } from 'store/region'; -import { cluster } from 'store/cluster'; -import urlQuery from 'store/url-query'; -import { observer } from 'mobx-react'; -import { modal } from 'store'; -import React from 'react'; -import { addRegion, modifyRegion } from 'lib/api'; -import { broker } from 'store/broker'; -import { IValueLabel } from 'types/base-type'; - -const regionFormItemLayout = { - labelCol: { - span: 7, - }, - wrapperCol: { - span: 11, - }, -}; - -@observer -export class Region extends React.Component { - public componentDidMount() { - cluster.getClusters(); - broker.initBrokerOptions(urlQuery.clusterId); - } - - public handleSubmit = (e: React.MouseEvent) => { - e.preventDefault(); - this.props.form.validateFieldsAndScroll((err: any, values: any) => { - if (err) return; - const commonFn = (fn: any) => { - fn.then(() => { - message.success(this.getTips()); - region.getRegions(urlQuery.clusterId); - modal.close(); - }); - }; - modal.regionData ? - commonFn(modifyRegion(Object.assign(values, { regionId: modal.regionData.regionId }))) : commonFn(addRegion(values)); - }); - } - - public getTips() { - if (modal.regionData) return '修改成功'; - return '添加成功'; - } - - public getTitle() { - if (modal.regionData) return '修改Region'; - return '添加Region'; - } - - public render() { - const { getFieldDecorator } = this.props.form; - let title = '新增Region'; - if (modal.regionData) title = '更新Region'; - const regionData = modal.regionData || {} as IRegionData; - return ( - -
    - - - {getFieldDecorator('regionName', { - rules: [{ required: true, message: '请输入Region名称' }], - initialValue: regionData.regionName, - })( - , - )} - - - - - {getFieldDecorator('clusterId', { - rules: [{ required: true, message: '请选择集群' }], - initialValue: urlQuery.clusterId, - })( - , - )} - - - - - {getFieldDecorator('brokerIdList', { - rules: [{ required: true, message: '请输入brokerList' }], - initialValue: regionData.brokerIdList, - })( - , - )} - - - - - {getFieldDecorator('status', { - initialValue: regionData.status || 0, - })( - , - )} - - - - - {getFieldDecorator('level', { - initialValue: regionData.level || 0, - })( - , - )} - - - - - {getFieldDecorator('description', { - rules: [{ required: false }], - initialValue: regionData.description, - })( - , - )} - - - -
    - ); - } -} - -export default Form.create({ name: 'Region' })(Region); diff --git a/console/src/container/modal/reset-offset.tsx b/console/src/container/modal/reset-offset.tsx deleted file mode 100644 index 45154f6e..00000000 --- a/console/src/container/modal/reset-offset.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Input, Select, DatePicker, Col, Button } from 'component/antd'; -import { modal } from 'store/modal'; - -const Option = Select.Option; - -const topicFormItemLayout = { - labelCol: { - span: 8, - }, - wrapperCol: { - span: 16, - }, -}; - -class ResetOffset extends React.Component { - public handleSubmit = () => { - debugger - } - - public render() { - const { getFieldDecorator } = this.props.form; - return ( - -
    - -
    - - - - - {/* - - - - */} - - - - - - - - - - - - - - - - - - - ); - } -} - -export default Form.create({ name: 'topic' })(ResetOffset); diff --git a/console/src/container/modal/task-new.tsx b/console/src/container/modal/task-new.tsx deleted file mode 100644 index 91ec125a..00000000 --- a/console/src/container/modal/task-new.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Input, Select, notification, InputNumber, Switch, Icon, Tooltip, Col } from 'component/antd'; -import { modal } from 'store/modal'; -import { cluster } from 'store/cluster'; -import { executeTask, modifyTask } from 'lib/api'; -import { operation, ITask } from 'store/operation'; -import { observer } from 'mobx-react'; -import { IValueLabel } from 'types/base-type'; -import { topic } from 'store/topic'; -import { broker } from 'store/broker'; - -const topicFormItemLayout = { - labelCol: { - span: 7, - }, - wrapperCol: { - span: 11, - }, -}; - -@observer -class Task extends React.Component { - public handleSubmit = () => { - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - const { throttle, partitionIdList } = values; - values.throttle = throttle * 1024 * 1024; - values.partitionIdList = typeof partitionIdList === 'string' ? values.partitionIdList.split(',') : []; - if (this.getDisabled()) { - const { taskId } = operation.taskDetail; - modifyTask({ throttle: values.throttle, taskId, action: 'modify' }).then(() => { - notification.success({ message: '修改成功' }); - operation.getTask(); - modal.close(); - }); - } else { - executeTask(values).then(() => { - notification.success({ message: '迁移任务创建成功' }); - operation.getTask(); - modal.close(); - }); - } - }); - } - - public getDisabled = () => !!operation.taskDetail; - - public initSelection = (value: number) => { - topic.getTopicList(value); - broker.initBrokerOptions(value); - } - - public filterSelection = (input: string, option: any) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0; - - public test = (): any => { - if (modal.id === 'showTaskDetail') return null; - } - public render() { - const disabled = this.getDisabled(); - const { getFieldDecorator } = this.props.form; - const initialData = operation.taskDetail || {} as ITask; - const isModify = modal.id === 'showTaskDetail'; - return ( - -
    - - - {getFieldDecorator('clusterId', { - rules: [{ required: true, message: '请选择集群' }], - initialValue: initialData.clusterId, - })( - , - )} - - - - - {getFieldDecorator('topicName', { - rules: [{ required: true, message: '请选择Topic' }], - initialValue: initialData.topicName, - })( - , - )} - - - - - {getFieldDecorator('partitionIdList', { - initialValue: initialData.partitionIdList || [], - })( - , - )} - - - - - 流量上限  - - - - } - > - {getFieldDecorator('throttle', { - rules: [{ required: true, message: '请输入限流值' }], - initialValue: +(initialData.throttle / (1024 * 1024)).toFixed(2) || 1, - })( - , - )} - MB/s - - - { - isModify ? ( - -
    - 分区列表  - 无色:待迁移
    半绿:迁移中
    全绿:迁移成功
    红色:迁移失败}> - -
    : - -
    -
      - {initialData.regionList && initialData.regionList.map((i, index) => { - return
    • 分区{i[0]}: {i[1].join(',')} -
    • ; - })} -
    - - - ) : null - } - { - !disabled ? ( - <> - - - {getFieldDecorator('brokerIdList', { - rules: [{ required: true, message: '请输入broker' }], - })( - , - )} - - - - - {getFieldDecorator('description', { - rules: [{ required: true, message: '请输入迁移说明' }], - })( - , - )} - - - - ) : null - } - - - ); - } -} - -export default Form.create({ name: 'task' })(Task); diff --git a/console/src/container/modal/topic-create.tsx b/console/src/container/modal/topic-create.tsx deleted file mode 100644 index de060efd..00000000 --- a/console/src/container/modal/topic-create.tsx +++ /dev/null @@ -1,220 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Input, Select, InputNumber, notification, Switch } from 'component/antd'; -import { modal } from 'store/modal'; -import { cluster } from 'store/cluster'; -import { adminCreateTopic, modifyTopic } from 'lib/api'; -import { ITopic, IValueLabel } from 'types/base-type'; -import { operation } from 'store/operation'; -import { broker } from 'store/broker'; -import urlQuery from 'store/url-query'; -import { observer } from 'mobx-react'; -import { topic } from 'store/topic'; -import { getCookie } from 'lib/utils'; - -const topicFormItemLayout = { - labelCol: { - span: 7, - }, - wrapperCol: { - span: 11, - }, -}; - -const bussDesc = `概要描述Topic的数据源, Topic数据的生产者/消费者, Topic的申请原因及备注信息等。`; - -@observer -class Topic extends React.Component { - public state = { - loading: false, - targetType: false, - }; - - public getDisabled = () => !!modal.topicData; - - public handleTarget = (targetType: boolean) => { - this.setState({ targetType }); - } - - public handleSubmit = () => { - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - const { principalList, retentionTime } = values; - values.principalList = typeof principalList === 'string' ? principalList.split(',') : values.principalList; - values.retentionTime = retentionTime * 3600000; - this.setState({ loading: true }); - const fn = this.getDisabled() ? modifyTopic : adminCreateTopic; - fn(values).then(data => { - topic.getAdminTopics(urlQuery.clusterId); - notification.success(this.getDisabled() ? { message: '修改Topic成功' } : { message: 'Topic创建成功' }); - modal.close(); - }, (err) => { - this.setState({ loading: false }); - }); - }); - } - public componentDidMount() { - operation.initRegionOptions(urlQuery.clusterId); - broker.initBrokerOptions(urlQuery.clusterId); - } - - public render() { - const { getFieldDecorator } = this.props.form; - const { loading } = this.state; - const initialData = modal.topicData || {} as ITopic; - const disabled = this.getDisabled(); - return ( - -
    - - - {getFieldDecorator('clusterId', { - rules: [{ required: true, message: '请选择集群' }], - initialValue: +urlQuery.clusterId, - })( - , - )} - - - - - {getFieldDecorator('topicName', { - rules: [{ required: true, message: '请输入Topic 名称' }, - { pattern: /^[a-zA-Z0-9_-]{1,64}$/, message: '格式不正确' }], - initialValue: initialData.topicName, - })( - , - )} - - - - - {getFieldDecorator('principalList', { - rules: [{ required: true, message: '请输入负责人' }], - initialValue: disabled ? initialData.principalList || ' ' : getCookie('username'), - })( - , - )} - - - - - {getFieldDecorator('retentionTime', { - rules: [{ required: true, message: '请输入保存时间' }], - initialValue: disabled ? (initialData.retentionTime / 3600000).toFixed(0) : 24, - })( - , - )} - 小时 - - - {!disabled ? - <> - - - - - - - { - this.state.targetType ? ( - - {getFieldDecorator('regionIdList', { - rules: [{ required: true, message: '请输入选择' }], - })( - , - )} - - ) : ( - - {getFieldDecorator('brokerIdList', { - rules: [{ required: true, message: '请输入broker' }], - })( - , - )} - - ) - } - - : null - } - - - {getFieldDecorator('partitionNum', { - rules: [{ required: true, message: '请输入partition数' }], - initialValue: topic.topicDetail && topic.topicDetail.partitionNum, - })( - , - )} - - - - - {getFieldDecorator('replicaNum', { - rules: [{ required: true, message: '请输入副本数' }], - initialValue: topic.topicDetail && topic.topicDetail.replicaNum, - })( - , - )} - - - - - {getFieldDecorator('properties', { - initialValue: initialData.properties, - })( - , - )} - - - - - {getFieldDecorator('description', { - initialValue: initialData.description || disabled && ' ', - })( - , - )} - - - -
    - ); - } -} - -export default Form.create({ name: 'topic' })(Topic); diff --git a/console/src/container/modal/topic-expand.tsx b/console/src/container/modal/topic-expand.tsx deleted file mode 100644 index 12b320d4..00000000 --- a/console/src/container/modal/topic-expand.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Input, Select, notification } from 'component/antd'; -import { modal } from 'store/modal'; -import { cluster } from 'store/cluster'; -import { addPartitionApprove } from 'lib/api'; -import { IBaseOrder } from 'types/base-type'; -import { topic } from 'store/topic'; -import { observer } from 'mobx-react'; -import { order } from 'store/order'; - -const topicFormItemLayout = { - labelCol: { - span: 7, - }, - wrapperCol: { - span: 11, - }, -}; -@observer -class Topic extends React.Component { - - public handleSubmit = () => { - if (!!modal.topicDetail) modal.close(); - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - if (modal.topicDetail) values.clusterId = modal.topicDetail.clusterId || values.clusterId; - addPartitionApprove(values).then(() => { - notification.success({ message: '申请成功' }); - order.getOrder(); - modal.close(); - }); - }); - } - - public filterSelection = (input: string, option: any) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0; - - public initSelection = (value: number) => { - topic.getTopicList(value); - cluster.getClusters(); - } - - public componentDidMount() { - const value = !!modal.topicDetail ? modal.topicDetail.clusterId : cluster.data[1].clusterId; - this.initSelection(value); - } - - public render() { - const { getFieldDecorator } = this.props.form; - const initialData = modal.topicDetail || {} as IBaseOrder; - const disabled = !!modal.topicDetail; - const isDetail = location.pathname.includes('topic_detai'); - return ( - -
    - - - {getFieldDecorator('clusterId', { - rules: [{ required: true, message: '请选择集群' }], - initialValue: +initialData.clusterId || +cluster.data[1].clusterId, - })( - , - )} - - - - - {getFieldDecorator('topicName', { - rules: [{ required: true, message: '请选择Topic' }], - initialValue: initialData.topicName, - })( - , - )} - - - - {getFieldDecorator('predictBytesIn', { - rules: [{ required: true, message: '请输入预估峰值流量' }], - initialValue: initialData.predictBytesIn, - })( - , - )} - MB/s - - { - !isDetail && disabled ? ( - <> - - - - - - - ) : null - } - - - {getFieldDecorator('description', { - rules: [{ required: true, message: '请输入申请原因' }], - initialValue: initialData.description, - })( - , - )} - - - -
    - ); - } -} - -export default Form.create({ name: 'topic' })(Topic); diff --git a/console/src/container/modal/topic-new.tsx b/console/src/container/modal/topic-new.tsx deleted file mode 100644 index 813d5040..00000000 --- a/console/src/container/modal/topic-new.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import * as React from 'react'; -import { Modal, Form, Row, Input, Select, InputNumber, notification } from 'component/antd'; -import { modal } from 'store/modal'; -import { cluster } from 'store/cluster'; -import { createTopic } from 'lib/api'; -import { ITopic } from 'types/base-type'; -import { operation } from 'store/operation'; -import urlQuery from 'store/url-query'; -import { getCookie } from 'lib/utils'; - -const topicFormItemLayout = { - labelCol: { - span: 7, - }, - wrapperCol: { - span: 11, - }, -}; - -const bussDesc = `概要描述Topic的数据源, Topic数据的生产者/消费者, Topic的申请原因及备注信息等。`; - -class Topic extends React.Component { - public state = { - loading: false, - }; - - public getDisabled = () => !!modal.topicData; - - public handleSubmit = () => { - if (this.getDisabled()) return modal.close(); - this.props.form.validateFields((err: Error, values: any) => { - if (err) return; - const { principalList, retentionTime } = values; - values.principalList = principalList.split(','); - values.retentionTime = retentionTime; - this.setState({ loading: true }); - createTopic(values).then(data => { - notification.success({ message: '申请Topic成功' }); - window.setTimeout(() => location.assign('/user/my_order'), 500); - modal.close(); - }, (err) => { - this.setState({ loading: false }); - }); - }); - } - - public render() { - const { getFieldDecorator } = this.props.form; - const disabled = this.getDisabled(); - const { loading } = this.state; - const initialData = modal.topicData || {} as ITopic; - return ( - -
    - - - {getFieldDecorator('clusterId', { - rules: [{ required: true, message: '请选择集群' }], - initialValue: +urlQuery.clusterId || initialData.clusterId || (cluster.data[1] && cluster.data[1].clusterId), - })( - , - )} - - - - - {getFieldDecorator('topicName', { - rules: [{ required: true, message: '请输入Topic 名称' }, - { pattern: /^[a-zA-Z0-9_-]{1,64}$/, message: '格式不正确' }], - initialValue: initialData.topicName, - })( - , - )} - - - - - {getFieldDecorator('principalList', { - rules: [{ required: true, message: '请输入负责人' }], - initialValue: disabled ? initialData.principals || ' ' : getCookie('username'), - })( - , - )} - - - - - {getFieldDecorator('retentionTime', { - rules: [{ required: true, message: '请输入保存时间' }], - initialValue: (initialData.retentionTime / 3600000) || 24, - })( - , - )} - 小时 - - - - - {getFieldDecorator('peakBytesIn', { - rules: [{ required: true, message: '请输入限流值' }], - initialValue: initialData.peakBytesIn || 1, - })( - , - )} - MB/s - - - - - {getFieldDecorator('description', { - rules: [{ required: true, message: '请输入业务说明' }], - initialValue: initialData.description || '', - })( - , - )} - - - -
    - ); - } -} - -export default Form.create({ name: 'topic' })(Topic); diff --git a/console/src/container/modify-user/index.less b/console/src/container/modify-user/index.less deleted file mode 100644 index a4df476e..00000000 --- a/console/src/container/modify-user/index.less +++ /dev/null @@ -1,45 +0,0 @@ -.fw-container { - position: absolute; - top: 0px; - bottom: 0px; - left: 0px; - right: 0px; - margin: auto; - height: 425px; - width: 415px; - display: flex; - justify-content: center; - align-items: center; - border: 1px solid rgba(0, 0, 0, 0.1); - background: #fff; - transition: all 500ms ease-in-out; - &:hover { - box-shadow: 0px 0px 14px 0px #afafaf; - } - .ant-form-item-control { - margin-bottom: 10px; - } - .ant-input { - height: 40px; - font-size: 14px; - border-radius: 0; - } - .style-button { - text-align: right; - .ant-btn { - width: 50%; - height: 40px; - border-radius: 0px; - border-right: 1px solid #fff; - } - .b-item { - text-align: right; - .ant-col-10 { - width: 55%; - button { - margin: 20px 10px 0 0; - } - } - } - } -} diff --git a/console/src/container/modify-user/index.tsx b/console/src/container/modify-user/index.tsx deleted file mode 100644 index e0009760..00000000 --- a/console/src/container/modify-user/index.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import * as React from 'react'; - -import { Form, Row, Input, notification, Button } from 'component/antd'; -import { modifyUser } from 'lib/api'; -import { getCookie } from 'lib/utils'; - -import './index.less'; - -class ModifyUser extends React.Component { - public handleSubmit = (e: React.MouseEvent) => { - e.preventDefault(); - this.props.form.validateFields((err: Error, values: any) => { - const username = getCookie('username'); - const role = getCookie('role'); - const { oldPassword, password } = values; - if (err) return; - modifyUser({ role, username, oldPassword, password }).then(() => { - notification.success({ message: '修改成功' }); - this.handleReset(); - }); - }); - } - - public comparePassword = (rule: any, value: any, callback: any) => { - const { form } = this.props; - if (value && value !== form.getFieldValue('password')) { - callback('两次密码不相同'); - } else { - callback(); - } - } - - public handleReset = () => { - this.props.form.resetFields(); - } - - public render() { - const { getFieldDecorator } = this.props.form; - return ( -
    -
    - - - {getFieldDecorator('oldPassword', { - rules: [{ required: true, message: '请输入原密码' }], - })( - , - )} - - - - - {getFieldDecorator('password', { - rules: [{ required: true, message: '请输入新密码' }], - })( - , - )} - - - - - {getFieldDecorator('confirm password', { - rules: [{ required: true, message: '请重新输入新密码' }, { - validator: this.comparePassword, - }], - })( - , - )} - - - - - - - - - -
    - ); - } -} - -export default Form.create({ name: 'modifyUser' })(ModifyUser); diff --git a/console/src/container/my-order/index.tsx b/console/src/container/my-order/index.tsx deleted file mode 100644 index fc9124d2..00000000 --- a/console/src/container/my-order/index.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import * as React from 'react'; - -import { Table, Tabs, Select, Input, notification, Modal } from 'component/antd'; -import { PaginationConfig } from 'antd/es/table/interface'; -import { modal } from 'store'; -import { observer } from 'mobx-react'; -import { order, tableStatusFilter } from 'store/order'; -import { cluster } from 'store/cluster'; -import { recallPartition, recallOrder } from 'lib/api'; -import moment from 'moment'; -import { handleTabKey, tableFilter } from 'lib/utils'; -import { SearchAndFilter } from 'container/cluster-topic'; -import { IBaseOrder } from 'types/base-type'; - -const TabPane = Tabs.TabPane; -const Search = Input.Search; -const Option = Select.Option; - -const handleRecallOrder = (record: IBaseOrder) => { - const flag = +location.hash.substr(1); - Modal.confirm({ - title: `确认撤回 Topic: ${record.topicName}${flag ? ' 扩容的' : ''}申请 ?`, - okText: '确定', - cancelText: '取消', - onOk: () => { - if (flag) { - recallPartition(record.orderId).then(() => { - notification.success({ message: '撤回成功' }); - order.getOrder(); - }); - } else { - recallOrder(record.orderId).then(() => { - notification.success({ message: '撤回成功' }); - order.getOrder(); - }); - } - }, - }); -}; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class MyOrder extends SearchAndFilter { - public state = { - searchKey: '', - filterStatusVisible: false, - filterClusterVisible: false, - filterSVisible: false, - filterCVisible: false, - }; - - public componentDidMount() { - order.getOrder(); - cluster.getClustersBasic(); - } - - public renderColumns = (data: IBaseOrder[], type: boolean) => { - const cluster = Object.assign({ - title: '集群名称', - dataIndex: 'clusterName', - key: 'clusterName', - filters: tableFilter(data, 'clusterName'), - onFilter: (value: string, record: IBaseOrder) => record.clusterName.indexOf(value) === 0, - }, this.renderColumnsFilter(type ? 'filterClusterVisible' : 'filterCVisible')); - - const status = Object.assign({ - title: '工单状态', - dataIndex: 'statusStr', - key: 'statusStr', - filters: tableStatusFilter, - onFilter: (value: string, record: IBaseOrder) => record.statusStr.indexOf(value) === 0, - render: (t: string) => {t}, - }, this.renderColumnsFilter(type ? 'filterStatusVisible' : 'filterSVisible')); - - return [ - { - title: '工单 ID', - dataIndex: 'orderId', - key: 'orderId', - sorter: (a: IBaseOrder, b: IBaseOrder) => a.orderId - b.orderId, - }, - cluster, - { - title: 'Topic 名称', - dataIndex: 'topicName', - key: 'topicName', - sorter: (a: IBaseOrder, b: IBaseOrder) => a.topicName.charCodeAt(0) - b.topicName.charCodeAt(0), - }, - { - title: 'Topic申请人', - dataIndex: 'applicant', - key: 'applicant', - sorter: (a: IBaseOrder, b: IBaseOrder) => a.principals.charCodeAt(0) - b.principals.charCodeAt(0), - }, - { - title: '申请时间', - dataIndex: 'gmtCreate', - key: 'gmtCreate', - sorter: (a: IBaseOrder, b: IBaseOrder) => a.gmtCreate - b.gmtCreate, - render: (t: number) => moment(t).format('YYYY-MM-DD HH:mm:ss'), - }, - status, - { - title: '审批人', - dataIndex: 'approver', - key: 'approver', - }, - { - title: '操作', - dataIndex: 'operation', - key: 'operation', - render: (text: string, r: IBaseOrder) => { - return ( - - 详情 - - {r.orderStatus === 0 ? 撤回 : null} - - ); - }, - }, - ]; - } - - public renderTopic() { - return ( -
    - ); - } - - public renderPartition() { - return ( -
    - ); - } - - public getData(origin: T[]) { - let data: T[] = []; - origin.forEach((d) => { - if (cluster.active === -1 || d.clusterId === cluster.active) { - return data.push(d); - } - }); - const { searchKey } = this.state; - - if (searchKey) { - data = data.filter((d) => d.topicName.includes(searchKey)); - } - - return data; - } - - public render() { - const activeKey = location.hash.substr(1); - return ( - <> -
      -
    • - {+activeKey ? '扩容申请' : 'Topic申请'} -
    • -
    • - -
    • -
    • -
    - - - {this.renderTopic()} - - - {this.renderPartition()} - - - - ); - } - - private onSearch = (e: React.ChangeEvent) => { - const searchKey = e.target.value.trim(); - this.setState({ - searchKey, - }); - } -} diff --git a/console/src/container/topic-detail/com.tsx b/console/src/container/topic-detail/com.tsx deleted file mode 100644 index 1930c2b7..00000000 --- a/console/src/container/topic-detail/com.tsx +++ /dev/null @@ -1,198 +0,0 @@ -import * as React from 'react'; -import { Table, DatePicker, Select, Button, PaginationConfig, notification, Spin, Tooltip } from 'component/antd'; -import echarts from 'echarts/lib/echarts'; -import { cluster } from 'store/cluster'; - -// 引入柱状图 -import 'echarts/lib/chart/line'; -// 引入提示框和标题组件 -import 'echarts/lib/component/tooltip'; -import 'echarts/lib/component/title'; -import 'echarts/lib/component/legend'; -import { observer } from 'mobx-react'; -import { topic, IConsumeInfo, ITopicStatusInfo } from 'store/topic'; -import { StatusGraghCom } from 'component/flow-table'; -import { IOptionType } from 'types/base-type'; -import moment from 'moment'; - -export const Base = observer(() => { - if (!topic.baseInfo) return null; - return ( -
      -
    • 负责人: - - {topic.baseInfo.principals} - -
    • -
    • 分区数: {topic.baseInfo.partitionNum} 个
    • -
    • 储存时间: {(topic.baseInfo.retentionTime / 3600000).toFixed(0)} 小时
    • -
    • 副本数: {topic.baseInfo.replicaNum} 个
    • -
    • 创建时间:{moment(topic.baseInfo.createTime).format('YYYY-MM-DD HH:mm:ss')}
    • -
    • Broker数:{topic.baseInfo.brokerNum} 个
    • -
    • 修改时间:{moment(topic.baseInfo.modifyTime).format('YYYY-MM-DD HH:mm:ss')}
    • -
    • Region:{topic.baseInfo.regionNames}
    • -
    • 描述信息: - - {topic.baseInfo.description} - -
    • -
    - ); -}); - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 6, - showTotal: (total) => `共 ${total} 条`, -}; - -interface IGroupProps { - data: IConsumeInfo[]; - pagination?: PaginationConfig; -} - -// export const Group = (props: IGroupProps) => { -// return ( -//
    -//
    -// -// ); -// }; - -export class Group extends React.Component { - public columns = [{ - title: '消费组名称', - dataIndex: 'consumerGroup', - key: 'consumerGroup', - width: '80%', - render: (t: string, r: IConsumeInfo) => this.renderOp(r), - }, { - title: 'location', - dataIndex: 'location', - key: 'location', - width: '20%', - render: (t: string) => t.toLowerCase(), - }, - ]; - - public renderOp = (record: IConsumeInfo) => { - return ( - - - {record.consumerGroup} - - - ); - } - - public render() { - return ( -
    -
    - - ); - } -} - -@observer -export class StatusGragh extends StatusGraghCom { - public getData = () => { - return topic.statusInfo; - } -} -@observer -export class NetWorkFlow extends React.Component { - public id: HTMLDivElement = null; - public chart: echarts.ECharts; - - public state = { - loading: true, - data: false, - type: 'normal', - }; - - public componentDidMount() { - this.chart = echarts.init(this.id); - cluster.initTime(); - this.handleSearch(); - } - - public handleApi = () => { - const { topicName, brokerId, clusterId } = this.props; - if (topicName) { - this.setState({ type: 'topic' }); - return cluster.getMetriceInfo(clusterId, topicName); - } - if (brokerId !== undefined) return cluster.getBrokerMetrics(clusterId, brokerId); - return cluster.getClusterMetricsHistory(clusterId); - } - - public handleSearch = () => { - const { startTime, endTime } = cluster; - if (startTime >= endTime) { - notification.error({ message: '开始时间不能大于或等于结束时间' }); - return false; - } - this.setState({ loading: true }); - this.handleApi().then(data => { - this.setState({ loading: false }); - this.setState({ data: !data.xAxis.data.length }); - this.chart.setOption(data as any, true); - }); - } - public handleChange = (value: IOptionType) => { - this.chart.setOption(cluster.changeType(value) as any, true); - } - - public handleStartTimeChange(value: moment.Moment) { - cluster.changeStartTime(value); - } - - public handleEndTimeChange(value: moment.Moment) { - cluster.changeEndTime(value); - } - - public render() { - return ( - <> -
    -
      -
    • - 开始时间 - -
    • -
    • - 结束时间 - -
    • -
    • - 类型 - -
    • -
    • - {/*
    • */} -
    -
    - - {this.state.data ?
    暂无数据
    : null} -
    this.id = id} /> - - - ); - } -} diff --git a/console/src/container/topic-detail/index.less b/console/src/container/topic-detail/index.less deleted file mode 100644 index 4a005673..00000000 --- a/console/src/container/topic-detail/index.less +++ /dev/null @@ -1,173 +0,0 @@ -p.k-title { - width: 100%; - font-size: 14px; - font-family: PingFangSC-Medium; - font-weight: 500; - color: rgba(0, 0, 0, 0.85); - height: 48px; - line-height: 48px; - background: rgba(0, 0, 0, 0.02); - padding-left: 24px; - margin: 0; -} -.right-flow { - .k-abs { - right: 24px; - cursor: pointer; - & > i { - margin-right: 5px; - } - } -} -.status-graph { - position: relative; - height: 48px; - width: 100%; - background: rgba(250, 250, 250, 1); -} -.topic-line-tool { - font-size: 14px; - font-family: PingFangSC-Regular; - font-weight: 400; - color: rgba(0, 0, 0, 0.85); - background: rgba(250, 250, 250); - li { - margin-right: 20px; - & > span.label { - padding-right: 10px; - } - } -} -.base-detail { - overflow: hidden; - width: 100%; - li { - float: left; - color: rgba(3, 2, 2, 0.85); - background: #fff; - line-height: 52px; - font-size: 14px; - font-family: PingFangSC-Regular; - white-space: nowrap; - &:nth-child(2n + 1) { - width: 65%; - span:first-child { - width: 30%; - } - } - &:nth-child(2n) { - width: 35%; - padding-left: 13px; - } - &.special { - width: 100%; - padding-left: 13px; - height: 52px; - span:first-child { - width: 20%; - text-align: left; - } - .principal { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - width: 70%; - display: inline-block; - vertical-align: top; - } - } - span:first-child { - display: inline-block; - font-size: 12px; - font-family: PingFangSC-Regular; - font-weight: 400; - color: rgba(0, 0, 0, 0.45); - width: 54%; - text-align: left; - } - } -} - -.k-row { - width: 100%; - overflow: hidden; - position: relative; - .k-abs { - position: absolute; - top: 15px; - } - .k-tab { - width: 100%; - height: 48px; - line-height: 48px; - background: rgba(0, 0, 0, 0.02); - padding: 0px 24px; - font-size: 14px; - font-family: PingFangSC-Medium; - font-weight: 500; - color: rgba(0, 0, 0, 0.85); - display: flex; - justify-content: space-between; - margin: 0; - } -} - -.k-top-row { - position: relative; - & + .k-top-row { - padding-left: 8px; - } - .group-search { - position: absolute; - top: 8px; - right: 24px; - width: 220px; - } -} - -.k-toolbar { - margin: 0; - position: absolute; - right: 0; - li { - display: inline-block; - vertical-align: middle; - line-height: 48px; - } -} - -.nav { - color: #3f3f3fc9; - p { - display: inline-block; - font-size: 20px; - height: 48px; - line-height: 48px; - font-weight: 800; - } -} -.t-button { - font-size: 12px; - button { - border: 1px solid #f38031; - color: #f38031; - margin-left: 10px; - background: transparent; - } -} -.group-detail { - .ant-table-body { - height: 270px; - } - .ant-table-placeholder { - display: none; - } -} - -.nothing-style { - position: absolute; - font-size: 18px; - color: #999; - top: 175px; - left: 520px; -} diff --git a/console/src/container/topic-detail/index.tsx b/console/src/container/topic-detail/index.tsx deleted file mode 100644 index 5d9232a5..00000000 --- a/console/src/container/topic-detail/index.tsx +++ /dev/null @@ -1,302 +0,0 @@ -import * as React from 'react'; -import './index.less'; -import { NetWorkFlow, StatusGragh, Group, Base } from './com'; -import { Table, Tabs, Button, PaginationConfig } from 'component/antd'; -import Url from 'lib/url-parser'; -import { topic, ITopicPartition, ITopicBroker } from 'store/topic'; -import { observer } from 'mobx-react'; -import { modal } from 'store'; -import { drawer } from 'store/drawer'; -import { handleTabKey } from 'lib/utils'; -import { getCookie } from 'lib/utils'; -import { SearchAndFilter } from 'container/cluster-topic'; -import { broker } from 'store/broker'; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class TopicDetail extends SearchAndFilter { - public clusterId: number; - public topicName: string; - public role: string; - - public brokerColumns = [{ - title: 'BrokerID', - key: 'brokerId', - dataIndex: 'brokerId', - sorter: (a: ITopicBroker, b: ITopicBroker) => a.brokerId - b.brokerId, - render: (t: string) => { - return ( - - {t} - - ); - }, - }, { - title: 'Host', - key: 'host', - dataIndex: 'host', - }, { - title: 'Leader个数', - key: 'leaderPartitionIdListLength', - dataIndex: 'leaderPartitionIdList', - render: (t: []) => { - return t.length; - }, - }, { - title: '分区LeaderID', - key: 'leaderPartitionIdList', - dataIndex: 'leaderPartitionIdList', - onCell: () => ({ - style: { - maxWidth: 180, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - cursor: 'pointer', - }, - }), - render: (t: []) => { - return t.map(i => {i}); - }, - }, { - title: '分区个数', - key: 'partitionNum', - dataIndex: 'partitionNum', - }, { - title: '分区ID', - key: 'partitionIdList', - dataIndex: 'partitionIdList', - onCell: () => ({ - style: { - maxWidth: 180, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - cursor: 'pointer', - }, - }), - render: (t: []) => { - return t.map(i => {i}); - }, - }, { - title: '操作', - render: (record: ITopicBroker) => { - return (查看详情); - }, - }]; - - public state = { - searchKey: '', - partitionKey: '', - brokerKey: '', - consumerKey: '', - filterVisible: false, - }; - - constructor(props: any) { - super(props); - const url = Url(); - this.clusterId = Number(url.search.clusterId); - this.topicName = url.search.topic; - this.role = getCookie('role'); - } - - public renderColumns = () => { - const underReplicated = Object.assign({ - title: '已同步', - key: 'underReplicated', - dataIndex: 'underReplicated', - filters: [{ text: '是', value: '0' }, { text: '否', value: '1' }], - onFilter: (value: string, record: ITopicPartition) => +record.underReplicated === +value, - render: (t: any) => {t ? '否' : '是'}, - }, this.renderColumnsFilter('filterVisible')); - - return [{ - title: '分区号', - key: 'partitionId', - dataIndex: 'partitionId', - sorter: (a: ITopicPartition, b: ITopicPartition) => a.partitionId - b.partitionId, - }, { - title: '偏移量', - key: 'offset', - dataIndex: 'offset', - }, { - title: 'LeaderBrokerID', - key: 'leaderBrokerId', - dataIndex: 'leaderBrokerId', - }, { - title: '副本BrokerID', - key: 'replicaBrokerIdList', - dataIndex: 'replicaBrokerIdList', - render: (t: []) => { - return t.map(i => {i}); - }, - }, { - title: 'ISR', - key: 'isrBrokerIdList', - dataIndex: 'isrBrokerIdList', - render: (t: []) => { - return t.map(i => {i}); - }, - }, { - title: '首选Leader副本', - key: 'preferredBrokerId', - dataIndex: 'preferredBrokerId', - }, - underReplicated]; - } - - public componentDidMount() { - const { topicName, clusterId } = this; - topic.getTopicBasicInfo(topicName, clusterId); - topic.getTopicStatusInfo(topicName, clusterId); - topic.getTopicConsumeInfo(clusterId, topicName); - topic.getTopicBroker(clusterId, topicName); - topic.getTopicPartition(clusterId, topicName); - } - - public updateStatus = () => { - topic.getTopicStatusInfo(this.topicName, this.clusterId); - } - - public getMoreDetail = (record: ITopicBroker) => { - return ( -
    -

    BrokerID: {record.brokerId}

    -

    Host:{record.host}

    -

    LeaderID: {record.leaderPartitionIdList.join(',')}(共{record.leaderPartitionIdList.length}个)

    -

    分区ID:{record.partitionIdList.join(',')}(共{record.partitionIdList.length}个)

    -
    - ); - } - - public renderMore() { - const data = this.state.brokerKey ? - topic.topicBrokers.filter((d) => d.host.includes(this.state.brokerKey)) : topic.topicBrokers; - return ( - <> -
    -
      -
    • Broker信息
    • - {this.renderSearch('请输入Host', 'brokerKey')} -
    -
    -
    - - - - ); - } - - public renderOperation() { - const { topicName, clusterId } = this; - return ( -
    - {location.hash.substr(1) === '2' ? : - <> - - - } -
    - ); - } - - public renderFlow() { - return ( - <> -
    -

    历史流量

    - -
    -
    -

    实时流量

    - - 刷新 - - -
    - - ); - } - - public renderMessage() { - const data = this.state.partitionKey ? - topic.topicPartitions.filter((d) => d.partitionId + '' === this.state.partitionKey) : topic.topicPartitions; - const consumerData = this.state.consumerKey ? - topic.consumeInfo.filter((d) => d.consumerGroup.includes(this.state.consumerKey)) : topic.consumeInfo; - return ( - <> -
    -
    -

    基本信息

    - -
    -
    -
      -
    • 消费组信息
    • - {this.renderSearch('请输入消费组名称', 'consumerKey')} -
    - -
    -
    - {+this.role ? this.renderMore() : null} -
    -
      -
    • 分区信息
    • - {this.renderSearch('请输入分区号', 'partitionKey')} -
    -
    -
    - - - - ); - } - - public renderTab() { }; - - public render() { - return ( - <> -
    -

    {this.topicName}

    -
    - - - {this.renderMessage()} - - - {this.renderFlow()} - - {this.renderTab()} - - - ); - } -} diff --git a/console/src/container/user-home/index.less b/console/src/container/user-home/index.less deleted file mode 100644 index 990d47ad..00000000 --- a/console/src/container/user-home/index.less +++ /dev/null @@ -1,73 +0,0 @@ -.content-container { - position: relative; - .table-operation { - a { - color: #f38031; - } - a + a { - margin-left: 10px; - } - } - .table-operation-bar { - position: absolute; - right: 24px; - z-index: 100; - li { - display: inline-block; - vertical-align: middle; - .ant-select { - width: 150px; - } - .ant-input-search { - width: 200px; - } - &.new-topic { - margin-right: 30px; - cursor: pointer; - & > i { - margin-right: 5px; - } - } - } - } - .k-collect { - width: 300px; - position: relative; - margin-bottom: 12px; - .ant-alert-close-icon { - top: 7px; - } - .k-coll-btn { - position: absolute; - top: 9px; - right: 15px; - } - } - .p-params { - display: inline-block; - padding: 0px 10px; - border-radius: 4px; - border: 1px solid rgba(217, 217, 217, 1); - margin: 0px 8px 8px 0px; - &-unFinished { - background: rgba(245, 34, 45, 0.2); - } - } -} - -.icon:hover { - position: relative; - .ant-checkbox-disabled { - &::after { - content: '已收藏'; - color: #fff; - background-color: rgba(0, 0, 0, 0.65); - position: absolute; - padding: 8px 0px; - width: 60px; - border-radius: 4px; - top: -30px; - left: 1px; - } - } -} diff --git a/console/src/container/user-home/index.tsx b/console/src/container/user-home/index.tsx deleted file mode 100644 index 859a0998..00000000 --- a/console/src/container/user-home/index.tsx +++ /dev/null @@ -1,286 +0,0 @@ -import * as React from 'react'; -import './index.less'; - -import { Table, Tabs, Alert, notification, PaginationConfig, Modal, Tooltip } from 'component/antd'; -import { modal } from 'store'; -import { cluster } from 'store/cluster'; -import { observer } from 'mobx-react'; -import { topic } from 'store/topic'; -import ReactDOM from 'react-dom'; -import { collect, uncollect } from 'lib/api'; -import { SearchAndFilter } from 'container/cluster-topic'; -import moment from 'moment'; -import { handleTabKey, tableFilter } from 'lib/utils'; -import { ITopic } from 'types/base-type'; - -const TabPane = Tabs.TabPane; - -const pagination: PaginationConfig = { - position: 'bottom', - showQuickJumper: true, - pageSize: 10, - showTotal: (total) => `共 ${total} 条`, -}; - -@observer -export class UserHome extends SearchAndFilter { - public state = { - searchKey: '', - filterCollVisible: false, - filterUnCollVisible: false, - filterFavorite: false, - }; - - public collRef: HTMLDivElement = null; - public uncollRef: HTMLDivElement = null; - - public rowSelection = { - onChange: (selectedRowKeys: string[], selectedRows: ITopic[]) => { - const num = selectedRows.length; - ReactDOM.render( - selectedRows.length ? ( - <> - - 收藏 - ) : null, - this.collRef, - ); - }, - getCheckboxProps: (record: any) => ({ disabled: record.favorite, className: 'icon' }), - }; - - public unrowSelection = { - onChange: (selectedRowKeys: string[], selectedRows: ITopic[]) => { - const num = selectedRows.length; - ReactDOM.render( - selectedRows.length ? ( - <> - - 取消收藏 - ) : null, - this.uncollRef, - ); - }, - }; - - public renderColumns = (data: ITopic[], type: boolean) => { - const cluster = Object.assign({ - title: '集群名称', - dataIndex: 'clusterName', - key: 'clusterName', - width: '12%', - filters: tableFilter(data, 'clusterName'), - onFilter: (value: string, record: ITopic) => record.clusterName.indexOf(value) === 0, - }, this.renderColumnsFilter(type ? 'filterCollVisible' : 'filterUnCollVisible')); - - const favorite = Object.assign({ - title: '状态', - dataIndex: 'favorite', - key: 'favorite', - filters: [{ text: '已收藏', value: 'true' }, { text: '未收藏', value: 'false' }], - onFilter: (value: string, record: ITopic) => record.favorite + '' === value, - render: (t: boolean) => t ? '已收藏' : '未收藏', - }, this.renderColumnsFilter('filterFavorite')); - - const columns = [ - { - title: 'Topic 名称', - dataIndex: 'topicName', - key: 'topicName', - width: 250, - onCell: () => ({ - style: { - maxWidth: 250, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - cursor: 'pointer', - }, - }), - sorter: (a: ITopic, b: ITopic) => a.topicName ? a.topicName.charCodeAt(0) - b.topicName.charCodeAt(0) : null, - render: (t: string, r: ITopic) => { - return ( - - {t} - ); - }, - }, - cluster, - { - title: '分区数', - dataIndex: 'partitionNum', - key: 'partitionNum', - width: 120, - sorter: (a: ITopic, b: ITopic) => b.partitionNum - a.partitionNum, - }, - { - title: '流入(KB/s)', - dataIndex: 'byteIn', - key: 'byteIn', - width: 120, - sorter: (a: ITopic, b: ITopic) => b.byteIn - a.byteIn, - render: (t: number) => (t / 1024).toFixed(2), - }, - { - title: '流入(QPS)', - dataIndex: 'produceRequest', - key: 'produceRequest', - width: 120, - sorter: (a: ITopic, b: ITopic) => b.produceRequest - a.produceRequest, - render: (t: number) => t.toFixed(2), - }, - { - title: '负责人', - dataIndex: 'principals', - key: 'principals', - width: 120, - onCell: () => ({ - style: { - maxWidth: 100, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - cursor: 'pointer', - }, - }), - render: (t: string) => {t}, - sorter: (a: ITopic, b: ITopic) => - a.principals && b.principals ? a.principals.charCodeAt(0) - b.principals.charCodeAt(0) : (-1), - }, - { - title: '修改时间', - dataIndex: 'updateTime', - key: 'updateTime', - width: '15%', - sorter: (a: ITopic, b: ITopic) => a.updateTime - b.updateTime, - render: (t: number) => moment(t).format('YYYY-MM-DD HH:mm:ss'), - }, - favorite, - ]; - if (!type) return columns.splice(0, columns.length - 1); - return columns; - } - - public renderCollection(favData: ITopic[]) { - return ( -
    - ); - } - - public renderList(data: ITopic[]) { - return ( -
    - ); - } - - public componentDidMount() { - if (cluster.data.length === 0) { - cluster.getClustersBasic(); - } - - if (topic.data.length === 0) { - topic.getTopics(); - } - } - - public collect = (selectedRowKeys: ITopic[]) => { - collect(selectedRowKeys.map(s => ({ clusterId: s.clusterId, topicName: s.topicName } as ITopic))).then(() => { - ReactDOM.unmountComponentAtNode(this.collRef); - topic.getTopics(); - notification.success({ message: '收藏成功' }); - }); - } - - public uncollect = (selectedRowKeys: ITopic[]) => { - Modal.confirm({ - title: `确认取消收藏?`, - okText: '确定', - cancelText: '取消', - onOk: () => { - uncollect(selectedRowKeys.map(s => ({ clusterId: s.clusterId, topicName: s.topicName } as ITopic))).then(() => { - ReactDOM.unmountComponentAtNode(this.uncollRef); - notification.success({ message: '取消收藏成功' }); - topic.getTopics(); - }); - }, - }); - } - - public getData(origin: T[]) { - let data: T[] = []; - origin.forEach((d) => { - if (cluster.active === -1 || d.clusterId === cluster.active) { - return data.push(d); - } - }); - const { searchKey } = this.state; - - if (searchKey) { - data = origin.filter((d) => d.topicName.includes(searchKey) || - (d.principals && d.principals.includes(searchKey))); - } - - return data; - } - - public renderTable() { - return ( - - -
    this.uncollRef = id} /> - {this.renderCollection(this.getData(topic.favData))} - - -
    this.collRef = id} /> - {this.renderList(this.getData(topic.data))} - - - ); - } - - public renderClusterTopic() { - return ( - <> - {this.renderCluster()} - {this.renderSearch('请输入Topic名称或者负责人')} - - ); - } - - public render() { - const isAdmin = location.pathname.includes('admin'); - return ( - <> -
      -
    • - {`Topic${isAdmin ? '创建' : '申请'}`} -
    • - {this.renderClusterTopic()} -
    - {this.renderTable()} - - ); - } -} diff --git a/console/src/lib/api.ts b/console/src/lib/api.ts deleted file mode 100644 index d3b9e294..00000000 --- a/console/src/lib/api.ts +++ /dev/null @@ -1,379 +0,0 @@ -import fetch from './fetch'; -import { INewCluster, ITopic, IAlarmBase, IDilation, ITaskBase, IRebalance, IOrderTopic, IUser, ISample, IDeleteTopic, IOffset } from 'types/base-type'; -import { IRegionData } from 'store/region'; - -export const getClusters = (cluster?: number) => { - return fetch(`/clusters${cluster ? '/' + cluster : ''}`); -}; - -export const getTopic = (clusterId?: number, favorite?: boolean) => { - const query = !clusterId && favorite === undefined ? '/topics' : - (clusterId ? `/topics?clusterId=${clusterId}` : `/topics?favorite=${favorite}`); - return fetch(query); -}; - -export const collect = (topicFavoriteList: ITopic[]) => { - return fetch('/topics/favorite', { - body: { - topicFavoriteList, - }, - }); -}; - -export const uncollect = (topicFavoriteList: ITopic[]) => { - return fetch('/topics/favorite', { - method: 'DELETE', - body: { - topicFavoriteList, - }, - }); -}; - -export const getTopicBasicInfo = (topicName: string, clusterId: number) => { - return fetch(`/${clusterId}/topics/${topicName}/basic-info`); -}; - -export const getTopicConsumeInfo = (clusterId: number, topicName: string) => { - return fetch(`/${clusterId}/topics/${topicName}/consumer-groups`); -}; - -export const getConsumeInfo = (clusterId: number) => { - return fetch(`/${clusterId}/consumers/consumer-groups`); -}; - -export const getTopicStatusInfo = (topicName: string, clusterId: number) => { - return fetch(`/${clusterId}/topics/${topicName}/metrics`); -}; - -export const getGroupInfo = (topicName: string, clusterId: number, group: string, location: string) => { - return fetch(`/${clusterId}/consumers/${group}/topics/${topicName}/consume-detail?location=${location}`); -}; - -export const getTopicOrder = () => { - return fetch('/orders/topic'); -}; - -export const getPartitionOrder = () => { - return fetch('/orders/partition'); -}; - -export const getAlarm = () => { - return fetch(`/alarms/alarm-rules`); -}; - -export const createTopic = (params: ITopic) => { - return fetch('/orders/topic', { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const getRegions = (clusterId: number) => { - return fetch(`/admin/${clusterId}/regions`); -}; - -export const delRegion = (regionId: number) => { - return fetch(`/admin/regions/${regionId}`, { - method: 'DELETE', - }); -}; - -export const addRegion = (params: IRegionData) => { - return fetch(`/admin/regions/region`, { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const modifyRegion = (params: IRegionData) => { - return fetch(`/admin/regions/region`, { - method: 'PUT', - body: JSON.stringify(params), - }); -}; - -export const topicDilatation = (params: IDilation) => { - return fetch('/admin/utils/topic/dilatation', { - method: 'PUT', - body: JSON.stringify(params), - }); -}; - -export const addAlarm = (params: IAlarmBase) => { - return fetch('/alarms/alarm-rule', { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const modifyAlarm = (params: IAlarmBase) => { - return fetch('/alarms/alarm-rule', { - method: 'PUT', - body: JSON.stringify(params), - }); -}; - -export const deleteAlarm = (alarmRuleId: number) => { - return fetch(`/alarms/alarm-rule?alarmRuleId=${alarmRuleId}`, { - method: 'DELETE', - }); -}; - -export const recallOrder = (orderId: number) => { - return fetch(`/orders/topic?orderId=${orderId}`, { - method: 'DELETE', - }); -}; - -export const getBrokerBaseInfo = (clusterId: number, brokerId: number) => { - return fetch(`/${clusterId}/brokers/${brokerId}/basic-info`); -}; - -export const getBrokerList = (clusterId: number) => { - return fetch(`/${clusterId}/brokers/overview`); -}; - -export const getTopicBroker = (clusterId: number, topicName: string) => { - return fetch(`/${clusterId}/topics/${topicName}/brokers`); -}; - -export const getTopicPartition = (clusterId: number, topicName: string) => { - return fetch(`/${clusterId}/topics/${topicName}/partitions`); -}; - -export const getBrokerNetwork = (clusterId: number) => { - return fetch(`/clusters/${clusterId}/metrics`); -}; - -export const getOneBrokerNetwork = (clusterId: number, brokerId: number) => { - return fetch(`/${clusterId}/brokers/${brokerId}/metrics`); -}; - -export const getBrokerPartition = (clusterId: number) => { - return fetch(`/${clusterId}/brokers/overall`); -}; - -export const getBrokerTopic = (clusterId: number, brokerId: number) => { - return fetch(`/${clusterId}/brokers/${brokerId}/topics`); -}; - -export const getController = (clusterId: number) => { - return fetch(`/clusters/${clusterId}/controller-history`); -}; - -export const getConsumeGroup = (clusterId: number, consumerGroup: string, location: string) => { - return fetch(`/${clusterId}/consumer/${consumerGroup}/topics?location=${location}`); -}; - -export const newCluster = (cluster: INewCluster) => { - return fetch(`/clusters`, { - method: 'POST', - body: JSON.stringify(cluster), - }); -}; - -export const modifyCluster = (cluster: INewCluster) => { - return fetch(`/clusters`, { - method: 'PUT', - body: JSON.stringify(cluster), - }); -}; - -export const getKafkaVersion = () => { - return fetch(`/clusters/kafka-version`); -}; - -export const getClusterMetricsHistory = (clusterId: number, startTime: string, endTime: string) => { - return fetch(`/clusters/${clusterId}/metrics-history?startTime=${startTime}&endTime=${endTime}`); -}; - -export const getPartitions = (clusterId: number, brokerId: number) => { - return fetch(`/${clusterId}/brokers/${brokerId}/partitions`); -}; - -export const getBrokerKeyMetrics = (clusterId: number, brokerId: number, startTime: string, endTime: string) => { - return fetch(`/${clusterId}/brokers/${brokerId}/key-metrics?startTime=${startTime}&endTime=${endTime}`); -}; - -export const getTask = (value?: number) => { - return fetch(`/admin/migration/tasks${value ? '/' + value : ''}`); -}; - -export const executeTask = (params: ITaskBase) => { - return fetch('/admin/migration/tasks', { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const modifyTask = (params: ITaskBase) => { - return fetch('/admin/migration/tasks', { - method: 'PUT', - body: JSON.stringify(params), - }); -}; - -export const getAdminTopicOrder = () => { - return fetch('/admin/orders/topic'); -}; - -export const getAdminPartitionOrder = (orderId?: number) => { - return fetch(`/admin/orders/partition${orderId ? '?orderId=' + orderId : ''}`); -}; - -export const getRebalanceStatus = (clusterId: number) => { - return fetch(`/admin/utils/rebalance/clusters/${clusterId}/status`); -}; - -export const addRebalance = (params: IRebalance) => { - return fetch('/admin/utils/rebalance', { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const getBrokerTopicAnalyzer = (clusterId: number, brokerId: number) => { - return fetch(`/${clusterId}/brokers/${brokerId}/analysis`); -}; - -export const addTopicApprove = (params: IOrderTopic) => { - return fetch('/admin/orders/topic', { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const addAdminPartition = (params: IOrderTopic) => { - return fetch('/admin/orders/partition', { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const addPartitionApprove = (params: IOrderTopic) => { - return fetch('/orders/partition', { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const getUsers = () => { - return fetch('/admin/accounts'); -}; - -export const addUser = (params: IUser) => { - return fetch('/admin/accounts/account', { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const deleteUser = (username: string) => { - return fetch(`/admin/accounts/account?username=${username}`, { - method: 'DELETE', - }); -}; - -export const modifyUser = (params: IUser) => { - return fetch('/admin/accounts/account', { - method: 'PUT', - body: JSON.stringify(params), - }); -}; - -export const getLogin = () => { - return fetch('/login/loginPage'); -}; - -export const userLogin = (params: IUser) => { - return fetch('/login/login', { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const userLogoff = (value: string) => { - return fetch(`/login/logoff?username=${value}`, { - method: 'POST', - }); -}; - -export const addSample = (params: ISample) => { - const {clusterId, topicName, ...rest} = params; - return fetch(`/${clusterId}/topics/${topicName}/sample`, { - method: 'POST', - body: JSON.stringify(rest), - }); -}; - -export const deleteTopic = (params: IDeleteTopic) => { - return fetch(`/admin/utils/topic`, { - method: 'DELETE', - body: JSON.stringify(params), - }); -}; - -export const modifyTopic = (params: ITopic) => { - return fetch('/admin/utils/topic/config', { - method: 'PUT', - body: JSON.stringify(params), - }); -}; - -export const resetOffset = (params: IOffset) => { - return fetch('/consumers/offsets', { - method: 'PUT', - body: JSON.stringify(params), - }); -}; - -export const getClustersBasic = () => { - return fetch('/clusters/basic-info'); -}; - -export const getAlarmConstant = () => { - return fetch('/alarms/alarm/constant'); -}; - -export const getTopicNameById = (clusterId: number) => { - return fetch(`/${clusterId}/topics/topic-names`); -}; - -export const deleteBroker = (clusterId: number, brokerId: number) => { - return fetch(`/${clusterId}/brokers/${brokerId}`, { - method: 'DELETE', - }); -}; - -export const recallPartition = (orderId: number) => { - return fetch(`/orders/partition?orderId=${orderId}`, { - method: 'DELETE', - }); -}; - -export const getBrokerNameList = (clusterId: number) => { - return fetch(`/${clusterId}/brokers/broker-metadata`); -}; - -export const adminCreateTopic = (params: ITopic) => { - return fetch('/admin/utils/topic', { - method: 'POST', - body: JSON.stringify(params), - }); -}; - -export const getAdminTopicDetail = (clusterId: number, topicName: string) => { - return fetch(`/admin/utils/${clusterId}/topics/${topicName}/detail`); -}; - -export const getTopicMetriceInfo = (clusterId: number, topicName: string, startTime: string, endTime: string) => { - return fetch(`/${clusterId}/topics/${topicName}/metrics-history?startTime=${startTime}&endTime=${endTime}`); -}; - -export const getBrokerMetrics = (clusterId: number, brokerId: number, startTime: string, endTime: string) => { - return fetch(`/${clusterId}/brokers/${brokerId}/metrics-history?startTime=${startTime}&endTime=${endTime}`); -}; - -export const getTopicMetaData = (clusterId: number, topicName: string) => { - return fetch(`/${clusterId}/topics/${topicName}/metadata`); -}; diff --git a/console/src/lib/charts-config.ts b/console/src/lib/charts-config.ts deleted file mode 100644 index 3b57654c..00000000 --- a/console/src/lib/charts-config.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { ISeriesOption, IOptionType, IClusterMetrics, IBrokerMetrics, IValueLabel } from 'types/base-type'; -import moment = require('moment'); - -export const getClusterMetricOption = (type: IOptionType, data: IClusterMetrics[]) => { - let name; - let series: ISeriesOption[]; - const date = data.map(i => moment(i.gmtCreate).format('YYYY-MM-DD HH:mm:ss')); - const legend = type === 'byteIn/byteOut' ? ['bytesInPerSec', 'bytesOutPerSec'] : - type === 'messageIn/totalProduceRequests' ? ['messagesInPerSec', 'totalProduceRequestsPerSec'] : [type]; - series = Array.from(legend, (item: IOptionType) => ({ - name: item, - type: 'line', - symbol: 'circle', - data: data.map(i => { - let seriesType = item as keyof IClusterMetrics; - if (type !== 'byteIn/byteOut' && type !== 'messageIn/totalProduceRequests') { - seriesType = item === 'byteRejected' ? 'bytesRejectedPerSec' : 'messagesInPerSec'; - } - return Number(i[seriesType]); - }), - })); - switch (type) { - case 'byteRejected': - name = 'B/s'; - break; - case 'messageIn/totalProduceRequests': - name = 'QPS'; - break; - case 'messageIn': - name = '条'; - break; - default: - if (series.map(i => isMB(i.data)).some(i => i === true)) { - name = 'MB/s'; - series.map(i => {i.data = i.data.map(ele => (ele / (1024 * 1024)).toFixed(2)) as []; }); - } else { - name = 'KB/s'; - series.map(i => {i.data = i.data.map(ele => (ele / 1024).toFixed(2)) as []; }); - } - } - return { - tooltip: { - trigger: 'axis', - padding: 10, - backgroundColor: 'rgba(0,0,0,0.7)', - borderColor: '#333', - textStyle: { - color: '#f3f3f3', - fontSize: '12px', - }, - }, - xAxis: { - boundaryGap: false, - data: date, - }, - legend: { - data: legend, - right: '1%', - top: '10px', - }, - yAxis: { - type: 'value', - name, - nameLocation: 'end', - nameGap: 10, - }, - grid: { - left: '1%', - right: '1%', - bottom: '3%', - top: '40px', - containLabel: true, - }, - series, - }; -}; - -export const getBrokerMetricOption = (charts: IValueLabel[], data: any) => { - const legend: string[] = []; - const seriesData = new Map(); - let date: string[] = []; - const valueData = Object.keys(data).map(item => { - legend.push(item); - return data[item]; - }); - - if (valueData.length) { - date = valueData[0].map((i: IBrokerMetrics) => moment(i.gmtCreate).format('HH:mm:ss')); - } - charts.forEach(item => { - if (!item.value) return false; - seriesData.set(item.value, legend.map((ele, index) => { - return { - name: ele, - type: 'line', - smooth: true, - symbol: 'circle', - data: valueData[index].map((i: IBrokerMetrics) => i[item.value as keyof IBrokerMetrics]), - }; - })); - }); - return charts.map(i => { - if (!i.value) return null; - return { - tooltip: { - trigger: 'axis', - padding: 10, - backgroundColor: 'rgba(0,0,0,0.7)', - borderColor: '#333', - textStyle: { - color: '#f3f3f3', - fontSize: '12px', - }, - }, - xAxis: { - boundaryGap: false, - data: date, - }, - legend: { - data: legend, - right: '1%', - top: '10px', - }, - yAxis: {}, - grid: { - left: '1%', - right: '1%', - bottom: '3%', - top: '40px', - containLabel: true, - }, - series: seriesData.get(i.value), - }; - }); -}; - -function isMB(arr: number[]) { - const filterData = arr.filter(i => i !== 0); - if (filterData.length) return filterData.reduce((cur, pre) => cur + pre) / filterData.length >= 100000; - return false; -} diff --git a/console/src/lib/fetch.ts b/console/src/lib/fetch.ts deleted file mode 100644 index 0be22f53..00000000 --- a/console/src/lib/fetch.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { notification } from 'component/antd'; - -const window = self.window; - -export interface IRes { - code: number; - message: string; - data: any; -} - -const checkStatus = (res: Response) => { - if (res.status === 200 && res.redirected) { - let url = res.url; - - if (!/^http(s)?:\/\//.test(url)) { - url = `${window.location.protocol}//${url}`; - } - - if (url) { - window.location.href = `${url}?jumpto=${encodeURIComponent(window.location.href)}`; - return null; - } - - return res; - } - return res; -}; - -const filter = (init: IInit) => (res: IRes) => { - if (res.code === 401) { - let url = res.data; - - if (!/^http(s)?:\/\//.test(url)) { - url = `${window.location.protocol}//${url}`; - } - - window.location.href = `${url}?jumpto=${encodeURIComponent(window.location.href)}`; - return null; - } - - if (res.code !== 0) { - if (!init.errorNoTips) { - notification.error({ - message: '错误', - description: res.message || '服务器错误,请重试!', - }); - } - throw res; - } - - return res.data; -}; - -const preFix = '/api/v1'; - -interface IInit extends RequestInit { - errorNoTips?: boolean; - body?: BodyInit | null | any; -} - -const csrfTokenMethod = ['POST', 'PUT', 'DELETE']; - -export default function fetch(url: string, init?: IInit) { - if (!init) init = {}; - - if (!init.credentials) init.credentials = 'include'; - if (init.body && typeof init.body === 'object') init.body = JSON.stringify(init.body); - if (init.body && !init.method) init.method = 'POST'; - if (init.method) init.method = init.method.toUpperCase(); - - if (csrfTokenMethod.includes(init.method)) { - init.headers = Object.assign({}, init.headers || { - 'Content-Type': 'application/json', - }); - } - - let realUrl = url; - if (!/^http(s)?:\/\//.test(url)) { - realUrl = `${preFix}${url}`; - } - return window - .fetch(realUrl, init) - .then(res => checkStatus(res)) - .then((res) => res.json()) - .then(filter(init)); -} diff --git a/console/src/lib/utils.ts b/console/src/lib/utils.ts deleted file mode 100644 index e4c6a24e..00000000 --- a/console/src/lib/utils.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { IFiler } from 'types/base-type'; - -export interface IMap { - [index: string]: string; -} -interface ICookie { - key: string; - value?: string; - time?: number; -} -export const getCookie = (key: string): string => { - const map: IMap = {}; - document.cookie.split(';').map((kv) => { - const d = kv.trim().split('='); - map[d[0]] = d[1]; - return null; - }); - return map[key]; -}; - -export const uuid = (): string => { - return 'c' + `${Math.random()}`.slice(2); -}; - -export const getRandomPassword = (len?: number) => { - const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - if (len) { - let res = ''; - for (let i = 0; i < len; i++) { - const id = Math.ceil(Math.random() * 62); - res += chars[id]; - } - return res; - } - return Math.ceil(Math.random() * 100000); -}; - -export const setCookie = (cData: ICookie[]) => { - const date = new Date(); - cData.forEach(ele => { - date.setTime(date.getTime() + (ele.time * 24 * 60 * 60 * 1000)); - const expires = 'expires=' + date.toUTCString(); - document.cookie = ele.key + '=' + ele.value + '; ' + expires + '; path=/'; - }); -}; - -export const deleteCookie = (cData: string[]) => { - setCookie(cData.map(i => ({key: i, value: '', time: -1}))); -}; - -export const handleTabKey = (key: string) => { - location.hash = key; -}; - -export const tableFilter = (data: T[], name: keyof T): IFiler[] => { - if (!data) return []; - const obj: any = {}; - return data.reduce((cur, pre) => { - if (!obj[pre[name]]) { - obj[pre[name]] = true; - cur.push({ text: pre[name], value: pre[name] }); - } - return cur; - }, []); -}; diff --git a/console/src/routers/page/admin/index.tsx b/console/src/routers/page/admin/index.tsx deleted file mode 100644 index 2e2d0106..00000000 --- a/console/src/routers/page/admin/index.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import * as React from 'react'; - -import 'component/antd'; -import { Header } from 'container/header'; -import { LeftMenu } from 'container/left-menu'; -import AllModalInOne from 'container/modal'; -import { TopicDetail } from 'container/topic-detail'; -import { BrokerDetail } from 'container/broker-detail'; -import { BrokerInfo } from 'container/broker-info'; -import { AdminHome } from 'container/admin-home'; -import AdminTopic from 'container/admin-topic'; -import { BrowserRouter as Router, Route } from 'react-router-dom'; -import { AdminOrder } from 'container/admin-order'; -import urlParser from 'lib/url-parser'; -import urlQuery from 'store/url-query'; -// import { AdminAlarm } from 'container/admin-alarm'; -import { AdminRegion } from 'container/admin-region'; -import { AdminController } from 'container/admin-controller'; -import { AdminConsume } from 'container/admin-consume'; -// import { ConsumerDetail } from 'container/admin-consume/detail'; -import { AdminOperation } from 'container/admin-operation'; -import { UserManage } from 'container/admin-usermanage'; -import ModifyUser from 'container/modify-user'; -import AllDrawerInOne from 'container/drawer'; -import { ClusterDetail } from 'container/admin-home/cluster-detail'; - -export default class Home extends React.Component { - constructor(props: any) { - super(props); - const search = urlParser().search; - urlQuery.clusterId = Number(search.clusterId); - urlQuery.brokerId = Number(search.brokerId); - urlQuery.group = search.group; - urlQuery.location = search.location; - urlQuery.topicName = search.topic; - } - - public render() { - const { match } = this.props; - const page = match.url; - return ( - <> -
    - -
    - -
    - - - - - {/* */} - - - - - - {/* */} - - - - -
    -
    -
    - - - - ); - } -} diff --git a/console/src/routers/page/home/index.tsx b/console/src/routers/page/home/index.tsx deleted file mode 100644 index bce5d649..00000000 --- a/console/src/routers/page/home/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import * as React from 'react'; - -import 'component/antd'; -import './index.less'; -import { Header } from 'container/header'; -import { LeftMenu } from 'container/left-menu'; -import { UserHome } from 'container/user-home'; -import { TopicDetail } from 'container/topic-detail'; -import AllModalInOne from 'container/modal'; -import AllDrawerInOne from 'container/drawer'; -import { MyOrder } from 'container/my-order'; -import { Alarm } from 'container/alarm'; -import { Consumer } from 'container/consumer'; -import ModifyUser from 'container/modify-user'; -import { BrowserRouter as Router, Route } from 'react-router-dom'; - -export default class Home extends React.Component { - - public render() { - const { match } = this.props; - const page = match.url; - return ( - <> -
    - -
    - -
    - - - - - - -
    -
    -
    - - - - ); - } -} diff --git a/console/src/routers/router.tsx b/console/src/routers/router.tsx deleted file mode 100644 index 57b3caf9..00000000 --- a/console/src/routers/router.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'; -import { hot } from 'react-hot-loader/root'; -import * as React from 'react'; -import { notification } from 'component/antd'; -import { getCookie } from 'lib/utils'; - -import Home from './page/home'; -import Admin from './page/admin'; -import Login from './page/login'; - -class RouterDom extends React.Component { - public render() { - return ( - - - - - - - - - - - - ); - } -} - -class RouteGuard extends React.Component { - public isLogin = getCookie('username'); - public isAdmin = getCookie('role'); - public render() { - const { component: Component, ...rest } = this.props; - const renderRoute = (props: any) => { - if (!this.isLogin) { - return ; - } else if (this.props.path.indexOf('admin') !== -1 && this.isAdmin === '0') { - notification.error({ message: '暂无权限,请联系管理员' }); - window.history.go(-1); - } else { - return ; - } - }; - return ( - - ); - } -} -export default hot(RouterDom); diff --git a/console/src/store/alarm.ts b/console/src/store/alarm.ts deleted file mode 100644 index 2ab1c6b7..00000000 --- a/console/src/store/alarm.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { observable, action } from 'mobx'; -import { getAlarm, getAlarmConstant } from 'lib/api'; -import { IAlarmBase } from 'types/base-type'; - -export interface IAlarm extends IAlarmBase { - gmtCreate: number; - gmtModify: number; - status: number; - key?: number; -} - -export interface IConstant { - conditionTypeList: []; - ruleTypeList: []; - notifyTypeList: []; - metricTypeList: []; -} - -class Alarm { - @observable - public data: IAlarm[] = []; - - @observable - public alarmConstant: IConstant = null; - - public curData: IAlarm = null; - - public setCurData(data: IAlarm) { - this.curData = data; - } - - @action.bound - public setAlarm(data: IAlarm[]) { - this.data = data.map((d, i) => { - d.key = i; - return d; - }); - } - - @action.bound - public setAlarmConstant(data: IConstant) { - this.alarmConstant = data; - } - - public getAlarm() { - getAlarm().then(this.setAlarm); - } - - public getAlarmConstant() { - getAlarmConstant().then(this.setAlarmConstant); - } -} - -export const alarm = new Alarm(); diff --git a/console/src/store/broker.ts b/console/src/store/broker.ts deleted file mode 100644 index f09470bf..00000000 --- a/console/src/store/broker.ts +++ /dev/null @@ -1,266 +0,0 @@ -import { observable, action } from 'mobx'; -import { getBrokerBaseInfo, getBrokerList, getBrokerNetwork, getBrokerPartition, getOneBrokerNetwork, getBrokerTopic, getPartitions, getBrokerKeyMetrics, getBrokerTopicAnalyzer, getBrokerNameList } from 'lib/api'; -import { IFlowInfo } from 'component/flow-table'; -import { ITopic, IValueLabel } from 'types/base-type'; -import moment from 'moment'; - -export interface IBrokerBaseInfo { - host: string; - jmxPort: number; - leaderCount: number; - partitionCount: number; - port: number; - startTime: number | string; - topicNum: number; -} - -export interface IBroker { - brokerId: number; - byteIn: number; - byteOut: number; - host: string; - jmxPort: number; - port: number; - startTime: number; - status: string; - regionName: string; -} - -export interface IBrokerNetworkInfo extends IFlowInfo { - produceRequest: number[]; - fetchConsumerRequest: number[]; -} - -export interface IBrokerPartition extends IBroker { - leaderCount: number; - partitionCount: number; - notUnderReplicatedPartitionCount: number; - underReplicatedPartitionCount?: number; - regionName: string; - bytesInPerSec: number; -} - -export interface IPartitions { - followerPartitionIdList: number[]; - leaderPartitionList: number[]; - topicName: string; - underReplicated: boolean; - underReplicatedPartitionsIdList: number[]; -} - -export interface ITopicStatus { - BytesOutPerSec_rate: number; - BytesInPerSec_rate: number; -} - -export interface IBrokerMetrics { - bytesIn?: number; - bytesOut?: number; - messagesIn?: number; - totalFetchRequests?: number; - totalProduceRequests?: number; -} - -export interface IAnalyzerData extends IBrokerMetrics { - topicAnalysisVOList: []; - baseTime?: number; - brokerId?: number; -} - -export type IOverviewKey = 'partitionCount' | 'leaderCount' | 'notUnderReplicatedPartitionCount'; - -interface IBrokerOption { - host: string; - brokerId: string; -} - -class Broker { - @observable - public loading: boolean = false; - - @observable - public brokerBaseInfo: IBrokerBaseInfo = {} as IBrokerBaseInfo; - - @observable - public list: IBroker[] = []; - - @observable - public network: IBrokerNetworkInfo = null; - - @observable - public oneNetwork: IBrokerNetworkInfo = null; - - @observable - public partitions: IBrokerPartition[] = []; - - @observable - public topics: ITopic[] = []; - - @observable - public topicPartitionsInfo: [] = []; - - @observable - public openKeys: string[] = []; - - @observable - public realPartitions: IBrokerPartition[] = []; - - @observable - public analyzerData: IAnalyzerData = {topicAnalysisVOList: []}; - - @observable - public viewType: IOverviewKey = 'partitionCount'; - - @observable - public regionOption: any = ['all']; - - @observable - public endTime = moment(); - - @observable - public startTime = moment().subtract(1, 'hour'); - - @observable - public BrokerOptions: IValueLabel[] = [{ value: null, label: '请选择Broker' }]; - - @action.bound - public setLoading(value: boolean) { - this.loading = value; - } - - @action.bound - public setBrokerBaseInfo(data: IBrokerBaseInfo) { - data.startTime = moment(data.startTime).format('YYYY-MM-DD HH:mm:ss'), - this.brokerBaseInfo = data; - } - - @action.bound - public setBrokerList(list: IBroker[]) { - this.list = list; - } - - @action.bound - public setBrokerNetWork(network: IBrokerNetworkInfo) { - if (!network) return false; - this.network = network; - } - - @action.bound - public setBrokerPartition(pars: IBrokerPartition[]) { - const res = new Map(); - this.partitions = pars.map(i => { - i.status = i.notUnderReplicatedPartitionCount ? '是' : '否'; - return i; - }); - this.realPartitions = pars; - this.regionOption = pars.filter((a) => !res.has(a.regionName) && res.set(a.regionName, 1)); - } - - @action.bound - public setOneBrokerNetwork(network: IBrokerNetworkInfo) { - this.oneNetwork = network; - } - - @action.bound - public setBrokerTopic(topics: ITopic[]) { - this.topics = topics; - } - - @action.bound - public setPartitionsInfo(pI: []) { - this.topicPartitionsInfo = pI; - } - - @action.bound - public handleOpen(key: string) { - if (this.openKeys.includes(key)) { - this.openKeys = this.openKeys.filter(k => k !== key); - } else { - this.openKeys.push(key); - this.openKeys = this.openKeys.slice(0); - } - } - - @action.bound - public handleOverview(type: IOverviewKey) { - this.viewType = type; - } - - @action.bound - public filterSquare(type: string) { - this.realPartitions = this.partitions; - if (type !== 'all') { - this.realPartitions = this.partitions.filter(i => i.regionName === type); - } - } - - @action.bound - public setBrokerTopicAnalyzer(data: IAnalyzerData) { - for (const item of Object.keys(data)) { - if (item === 'bytesIn' || item === 'bytesOut') data[item] = +(data[item] / (1024 * 1024)).toFixed(2); - } - this.analyzerData = data; - } - - @action.bound - public changeStartTime(value: moment.Moment) { - this.startTime = value; - } - - @action.bound - public changeEndTime(value: moment.Moment) { - this.endTime = value; - } - - @action.bound - public setBrokerOptions(data: IBrokerOption[]) { - this.BrokerOptions = data.map(i => ({ - label: `BrokerID: ${i.brokerId}, Host: ${i.host}`, - value: i.brokerId, - })); - } - - public getBrokerBaseInfo(clusterId: number, brokerId: number) { - getBrokerBaseInfo(clusterId, brokerId).then(this.setBrokerBaseInfo); - } - - public getBrokerList(clusterId: number) { - this.setLoading(true); - getBrokerList(clusterId).then(this.setBrokerList).finally(() => this.setLoading(false)); - } - - public getBrokerNetwork(clusterId: number) { - getBrokerNetwork(clusterId).then(this.setBrokerNetWork); - } - - public getBrokerPartition(clusterId: number) { - this.setLoading(true); - getBrokerPartition(clusterId).then(this.setBrokerPartition).finally(() => this.setLoading(false)); - } - - public getOneBrokerNetwork(clusterId: number, brokerId: number) { - getOneBrokerNetwork(clusterId, brokerId).then(this.setOneBrokerNetwork); - } - - public getBrokerTopic(clusterId: number, brokerId: number) { - getBrokerTopic(clusterId, brokerId).then(this.setBrokerTopic); - } - - public getPartitions(clusterId: number, brokerId: number) { - getPartitions(clusterId, brokerId).then(this.setPartitionsInfo); - } - - public getBrokerKeyMetrics(clusterId: number, brokerId: number, startTime: string, endTime: string) { - return getBrokerKeyMetrics(clusterId, brokerId, startTime, endTime); - } - - public getBrokerTopicAnalyzer(clusterId: number, brokerId: number) { - getBrokerTopicAnalyzer(clusterId, brokerId).then(this.setBrokerTopicAnalyzer); - } - - public initBrokerOptions = (clusterId: number) => { - getBrokerNameList(clusterId).then(this.setBrokerOptions); - } -} - -export const broker = new Broker(); diff --git a/console/src/store/cluster.ts b/console/src/store/cluster.ts deleted file mode 100644 index 34e957bd..00000000 --- a/console/src/store/cluster.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { observable, action } from 'mobx'; -import { getClusters, getKafkaVersion, getClusterMetricsHistory, getRebalanceStatus, getClustersBasic, getTopicMetriceInfo, getBrokerMetrics } from 'lib/api'; -import { getClusterMetricOption } from 'lib/charts-config'; -import { IClusterData, IClusterMetrics, IOptionType } from 'types/base-type'; - -import moment from 'moment'; - -class Cluster { - @observable - public data: IClusterData[] = []; - - @observable - public active: number = null; - - @observable - public kafkaVersions: string[] = []; - - @observable - public startTime: moment.Moment; - - @observable - public endTime: moment.Moment; - - @observable - public clusterMetrics: IClusterMetrics[] = []; - - @observable - public leaderStatus: string = ''; - - @observable - public type: IOptionType = 'byteIn/byteOut' ; - - @action.bound - public setData(data: IClusterData[]) { - data.unshift({ - clusterId: -1, - clusterName: '所有集群', - } as IClusterData); - this.data = data; - this.active = (this.data[0] || { clusterId: null }).clusterId; - } - - @action.bound - public changeCluster(data: number) { - this.active = data; - } - - @action.bound - public setKafkaVersion(data: string[]) { - this.kafkaVersions = data; - } - - @action.bound - public setChartsOpton(data: IClusterMetrics[]) { - this.clusterMetrics = data; - return this.changeType(this.type); - } - - @action.bound - public changeType(type: IOptionType) { - cluster.type = type; - return getClusterMetricOption(type, this.clusterMetrics); - } - - @action.bound - public changeStartTime(value: moment.Moment) { - this.startTime = value; - } - - @action.bound - public changeEndTime(value: moment.Moment ) { - this.endTime = value; - } - - @action.bound - public initTime() { - this.startTime = moment().subtract(1, 'hour'); - this.endTime = moment(); - } - - @action.bound - public setLeaderStatus(type: string) { - this.leaderStatus = type; - } - - public getClusters() { - getClusters().then(this.setData); - } - - public getClustersBasic() { - getClustersBasic().then(this.setData); - } - - public getKafkaVersions() { - getKafkaVersion().then(this.setKafkaVersion); - } - - public getClusterMetricsHistory(clusterId: number) { - return getClusterMetricsHistory(clusterId, - this.startTime.format('x'), - this.endTime.format('x')).then(this.setChartsOpton); - } - - public getMetriceInfo(clusterId: number, topicName: string) { - return getTopicMetriceInfo(clusterId, topicName, - this.startTime.format('x'), - this.endTime.format('x')).then(this.setChartsOpton); - } - - public getRebalance(clusterId: number) { - return getRebalanceStatus(clusterId).then((type) => { - this.setLeaderStatus(type); - if (type === 'RUNNING') { - window.setTimeout(() => { - this.getRebalance(clusterId); - }, 1000 * 2); - } - }); - } - - public getBrokerMetrics(clusterId: number, brokerId: number) { - return getBrokerMetrics(clusterId, brokerId, - this.startTime.format('x'), - this.endTime.format('x')).then(this.setChartsOpton); - } -} - -export const cluster = new Cluster(); diff --git a/console/src/store/controller.ts b/console/src/store/controller.ts deleted file mode 100644 index c102b43a..00000000 --- a/console/src/store/controller.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { observable, action } from 'mobx'; -import { getController } from 'lib/api'; - -export interface IController { - brokerId: number; - controllerTimestamp: number; - controllerVersion: number; - host: string; -} - -class Controller { - @observable - public data: IController[] = []; - - @action.bound - public setData(data: IController[]) { - this.data = data; - } - - public getController(clusterId: number) { - getController(clusterId).then(this.setData); - } -} - -export const controller = new Controller(); diff --git a/console/src/store/drawer.ts b/console/src/store/drawer.ts deleted file mode 100644 index 8dcd30de..00000000 --- a/console/src/store/drawer.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { observable, action } from 'mobx'; - -class Drawer { - @observable - public id: string = null; - - @observable - public topicData: any = null; - - @observable - public offsetDetail: any = null; - - @action.bound - public showResetOffset(r: any) { - this.id = 'showResetOffset'; - this.offsetDetail = r; - } - - @action.bound - public showTopicSample({ clusterId, topicName }: any) { - this.id = 'showTopicSample'; - this.topicData = { clusterId, topicName }; - } - - @action.bound - public close() { - this.id = null; - } -} - -export const drawer = new Drawer(); diff --git a/console/src/store/modal.ts b/console/src/store/modal.ts deleted file mode 100644 index e6098e69..00000000 --- a/console/src/store/modal.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { observable, action } from 'mobx'; -import { alarm, IAlarm } from './alarm'; -import { IRegionData } from './region'; -import { operation, ITask } from './operation'; -import { IClusterData, IBaseOrder, ITopic } from 'types/base-type'; -import { getAdminPartitionOrder, getAdminTopicDetail } from 'lib/api'; -import { IUserDetail } from './users'; -import { topic, IConsumeInfo } from './topic'; - -class Modal { - @observable - public id: string = null; - - @observable - public orderDetail: IBaseOrder = {} as IBaseOrder; - - @observable - public topicData: ITopic = null; - - public topicDetail: IBaseOrder = null; - public regionData: IRegionData = null; - public currentCluster: IClusterData = {} as IClusterData; - public userDetail: IUserDetail = null; - public consumberGroup: IConsumeInfo = null; - - @action.bound - public showNewTopic(r: ITopic) { - this.topicData = r; - this.id = 'showNewTopic'; - } - - @action.bound - public showNewCluster() { - this.id = 'showNewCluster'; - } - - @action.bound - public showModifyCluster(cluster: IClusterData) { - this.id = 'showModifyCluster'; - this.currentCluster = cluster; - } - - @action.bound - public setTopic(data: ITopic) { - this.topicData = data; - } - - @action.bound - public showAdimTopic(r: ITopic) { - this.id = 'showAdimTopic'; - this.topicData = r; - if (r) { - getAdminTopicDetail(r.clusterId, r.topicName).then(this.setTopic); - topic.getTopicMetaData(r.clusterId, r.topicName); - } - } - - @action.bound - public showAlarm(r: IAlarm) { - alarm.setCurData(r); - this.id = 'showAlarm'; - } - - @action.bound - public showRegion(r: IRegionData) { - this.id = 'showRegion'; - this.regionData = r; - } - - @action.bound - public showExpandTopic(data: IBaseOrder) { - this.topicDetail = data; - this.id = 'showExpandTopic'; - } - - @action.bound - public showExpandAdmin(data: IBaseOrder) { - this.topicDetail = data; - this.id = 'showExpandAdmin'; - } - - @action.bound - public showResetOffset() { - this.id = 'showResetOffset'; - } - - @action.bound - public showLeaderRebalance() { - this.id = 'showLeaderRebalance'; - } - - @action.bound - public showTask(value: ITask, type?: string) { - this.id = type === 'detail' ? 'showTaskDetail' : 'showTask'; - value ? operation.getTaskDetail(value.taskId) : operation.setTaskDetail(value); - } - - @action.bound - public showOrderApprove(value: any, type: string) { - this.id = type === 'showOrderApprove' ? 'showOrderApprove' : 'showOrderDetail'; - this.orderDetail = value; - } - - @action.bound - public setDetail(data: any) { - if (data[0]) this.orderDetail = data[0]; - } - - @action.bound - public showPartition(value: any, type: string) { - this.orderDetail = value; - this.id = type === 'showPartition' ? 'showPartition' : 'showPartitionDetail'; - getAdminPartitionOrder(value.orderId).then(this.setDetail); - } - - @action.bound - public showNewUser(data: IUserDetail) { - this.userDetail = data; - this.id = 'showNewUser'; - } - - @action.bound - public shoeTopicConfig(data: IBaseOrder) { - this.topicDetail = data; - this.id = 'shoeTopicConfig'; - } - - @action.bound - public showAlarmModify(r: IAlarm) { - alarm.setCurData(r); - this.id = 'showAlarmModify'; - } - - @action.bound - public showConsumerTopic(r: IConsumeInfo) { - this.consumberGroup = r; - this.id = 'showConsumerTopic'; - } - - @action.bound - public close() { - this.id = null; - this.currentCluster = {} as IClusterData; - } -} - -export const modal = new Modal(); diff --git a/console/src/store/operation.ts b/console/src/store/operation.ts deleted file mode 100644 index 9152342d..00000000 --- a/console/src/store/operation.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { observable, action } from 'mobx'; -import { getTask, getRegions } from 'lib/api'; -import { ITaskBase } from 'types/base-type'; - -interface IReassign { - [propname: string]: number[]; -} - -interface IMigration { - [index: string]: number; -} - -export const taskMap = ['待执行', '执行中', '迁移成功', '迁移失败', '已撤销']; - -export interface ITask extends ITaskBase { - clusterName: string; - gmtCreate: number; - operator: string; - reassignmentMap?: IReassign; - migrationStatus?: IMigration; - regionList?: Array<[string, number[]]>; -} - -class Operation { - @observable - public tasks: ITask[] = null; - - @observable - public taskDetail: ITask = null; - - @observable - public RegionOptions: any[] = ['请选择集群']; - - @action.bound - public setTask(data: ITask[]) { - this.tasks = data; - } - - @action.bound - public setTaskDetail(data: ITask) { - if (data) data.regionList = Object.keys(data.reassignmentMap).map(i => [i, data.reassignmentMap[i]]); - this.taskDetail = data; - } - - @action.bound - public setRegionOptions(data: any) { - this.RegionOptions = data.map((i: any) => ({ - value: i.regionId, - label: i.regionName, - })); - } - - public getTask() { - getTask().then(this.setTask); - } - - public initRegionOptions = (clusterId: number) => { - getRegions(clusterId).then(this.setRegionOptions); - } - - public getTaskDetail(value: number) { - getTask(value).then(this.setTaskDetail); - } -} - -export const operation = new Operation(); diff --git a/console/src/store/order.ts b/console/src/store/order.ts deleted file mode 100644 index 811a17bc..00000000 --- a/console/src/store/order.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { observable, action } from 'mobx'; -import { getTopicOrder, getPartitionOrder, getAdminTopicOrder, getAdminPartitionOrder } from 'lib/api'; -import { IBaseOrder } from 'types/base-type'; - -const statusMap = ['待审批', '通过', '拒绝', '撤销']; -export const tableStatusFilter = statusMap.map(i => ({text: i, value: i})); - -export interface IPartitionOrder extends IBaseOrder { - peakAvgBytesInPerSec: number; -} - -class Order { - @observable - public topicOrder: IBaseOrder[] = []; - - @observable - public partitionOrder: IPartitionOrder[] = []; - - @observable - public adminTopicOrder: IBaseOrder[] = []; - - @observable - public adminPartitionOrder: IPartitionOrder[] = []; - - @observable - public pendingTopic: number = 0; - - @observable - public pendingOrder: number = 0; - - @action - public mapData(data: any, type?: 'pendingTopic' | 'pendingOrder') { - this[type] = 0; - return data.map((d: any) => { - if (!d.orderStatus) this[type] += 1; - d.statusStr = statusMap[d.orderStatus]; - d.key = d.orderId; - return d; - }); - } - - @action.bound - public setTopicOrder(data: IBaseOrder[]) { - this.topicOrder = this.mapData(data); - } - - @action.bound - public setPartitionOrder(data: IPartitionOrder[]) { - this.partitionOrder = this.mapData(data); - } - - @action.bound - public setAdiminTopicOrder(data: IBaseOrder[]) { - this.adminTopicOrder = this.mapData(data, 'pendingTopic'); - } - - @action.bound - public setAdminPartitionOrder(data: IPartitionOrder[]) { - this.adminPartitionOrder = this.mapData(data, 'pendingOrder'); - } - - public getOrder() { - getTopicOrder().then(this.setTopicOrder); - getPartitionOrder().then(this.setPartitionOrder); - } - - public getAdminOrder() { - getAdminTopicOrder().then(this.setAdiminTopicOrder); - getAdminPartitionOrder().then(this.setAdminPartitionOrder); - } -} - -export const order = new Order(); diff --git a/console/src/store/region.ts b/console/src/store/region.ts deleted file mode 100644 index 4c41e1e9..00000000 --- a/console/src/store/region.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { observable, action } from 'mobx'; -import { getRegions, delRegion } from 'lib/api'; - -export const statusMap = ['废弃', '正常', '容量已满']; -export const levelMap = ['普通', '重要']; -export interface IRegionData { - brokerIdList: number[]; - clusterId: number; - description: string; - gmtCreate: number; - gmtModify: number; - level: number; - regionId: number; - regionName: string; - status: number; -} - -class Region { - @observable - public data: IRegionData[] = []; - - @action.bound - public setData(data: IRegionData[]) { - this.data = data; - } - - public getRegions(clusterId: number) { - getRegions(clusterId).then(this.setData); - } - - public delRegion(regionId: number) { - return delRegion(regionId); - } -} - -export const region = new Region(); diff --git a/console/src/store/topic.ts b/console/src/store/topic.ts deleted file mode 100644 index 3ee2489e..00000000 --- a/console/src/store/topic.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { observable, action } from 'mobx'; -import { getTopic, getTopicBasicInfo, getTopicConsumeInfo, getTopicStatusInfo, getGroupInfo, getConsumeGroup, addSample, getTopicBroker, getTopicPartition, getTopicNameById, getTopicMetaData } from 'lib/api'; -import { IFlowInfo } from 'component/flow-table'; -import urlQuery from './url-query'; -import { ITopic, IOffset, ISample } from 'types/base-type'; - -export interface ITopicBaseInfo { - brokerNum: number; - createTime: string; - description: string; - modifyTime: string; - partitionNum: number; - principals: string; - regionNames: string; - replicaNum: number; - retentionTime: number; - topicName: string; -} - -export interface IConsumeInfo { - location: string; - consumerGroup: string; - clusterId?: number; - key?: string; -} - -export interface ITopicStatusInfo extends IFlowInfo { - totalProduceRequest: number[]; -} - -export interface IGroupInfo { - clientId: string; - clusterId: number; - consumeOffset: number; - consumerGroup: string; - lag: number; - location: string; - partitionId: number; - partitionOffset: number; - topicName: string; - key?: string; -} - -export interface ITopicBroker { - brokerId: number; - host: string; - leaderPartitionIdList: number[]; - partitionIdList: number[]; - partitionNum: number; -} - -export interface ITopicPartition { - isrBrokerIdList: number[]; - leaderBrokerId: number; - leaderEpoch: number; - offset: number; - partitionId: number; - preferredBrokerId: number; - replicaBrokerIdList: number[]; - underReplicated: boolean; -} - -export interface IAdminExpand { - brokerIdList: number[]; - clusterId: number; - partitionNum: number; - replicaNum: number; - topicName: string; -} - -class Topic { - @observable - public data: ITopic[] = []; - - @observable - public favData: ITopic[] = []; - - @observable - public comsumeTopics: string[] = []; - - @observable - public baseInfo: ITopicBaseInfo = null; - - @observable - public consumeInfo: IConsumeInfo[] = []; - - @observable - public groupInfo: IGroupInfo[] = []; - - @observable - public statusInfo: ITopicStatusInfo = null; - - @observable - public sampleData: ISample[] = null; - - @observable - public topicBrokers: ITopicBroker[] = []; - - @observable - public topicPartitions: ITopicPartition[] = []; - - @observable - public topicNameList: string[] = []; - - @observable - public topicDetail: IAdminExpand = null; - - public currentTopicName = ''; - public currentClusterId: number = null; - public currentGroup: IOffset = null; - - @action.bound - public setData(data: ITopic[]) { - this.data = data.map((i, index) => { - i.key = index; - return i; - }); - } - - @action.bound - public setFavData(data: ITopic[]) { - this.favData = data.map((i, index) => { - i.key = index; - return i; - }); - } - - @action.bound - public setTopicBaseInfo(data: ITopicBaseInfo) { - this.baseInfo = data; - } - - @action.bound - public setTopicConsumeInfo(data: IConsumeInfo[]) { - this.consumeInfo = data.map(d => { - d.key = d.consumerGroup; - return d; - }); - } - - @action.bound - public setTopicStatusInfo(data: ITopicStatusInfo) { - this.statusInfo = data; - } - - @action.bound - public setGroupInfo(data: IGroupInfo[]) { - this.groupInfo = data.map(d => { d.key = d.clientId; return d; }); - } - - @action.bound - public setComsumeTopics(topics: string[]) { - this.comsumeTopics = topics; - } - - @action.bound - public setSampleData(data: ISample[]) { - this.sampleData = data; - } - - @action.bound - public setTopicBrokers(tb: ITopicBroker[]) { - this.topicBrokers = tb; - } - - @action.bound - public setTopicPartitions(tp: ITopicPartition[]) { - this.topicPartitions = tp; - } - - @action.bound - public setTopicNameList(data: string[]) { - this.topicNameList = data; - } - - @action.bound - public setTopicDetail(data: IAdminExpand) { - this.topicDetail = data; - } - - public setCurrent({ topicName, clusterId }: ITopic) { - this.currentTopicName = topicName; - this.currentClusterId = clusterId; - } - - public getTopics() { - getTopic(null, false).then(this.setData); - getTopic(null, true).then(this.setFavData); - } - - public getAdminTopics(clusterId: number) { - getTopic(clusterId).then(this.setData); - } - - public getTopicBasicInfo(topic: string, clusterId: number) { - getTopicBasicInfo(topic, clusterId).then(this.setTopicBaseInfo); - } - - public getTopicConsumeInfo(clusterId: number, topicName: string) { - getTopicConsumeInfo(clusterId, topicName).then(this.setTopicConsumeInfo); - } - - public getTopicStatusInfo(topic: string, clusterId: number) { - this.currentTopicName = topic; - this.currentClusterId = clusterId; - getTopicStatusInfo(topic, clusterId).then(this.setTopicStatusInfo); - } - - public getGroupInfo(topicName: string, clusterId: number, consumerGroup: string, location: string) { - this.currentGroup = { topicName, clusterId, consumerGroup, location: location.toLowerCase() }; - getGroupInfo(topicName, clusterId, consumerGroup, location).then(this.setGroupInfo); - } - - public getConsumeGroup(group: string, location: string) { - return getConsumeGroup(urlQuery.clusterId, group, location).then(this.setComsumeTopics); - } - - public addSample(params: ISample) { - return addSample(params).then(this.setSampleData); - } - - public getTopicBroker(clusterId: number, topicName: string) { - return getTopicBroker(clusterId, topicName).then(this.setTopicBrokers); - } - - public getTopicPartition(clusterId: number, topicName: string) { - return getTopicPartition(clusterId, topicName).then(this.setTopicPartitions); - } - - public getTopicList = (value: number) => { - getTopicNameById(value).then(this.setTopicNameList); - } - - public getTopicMetaData = (clusterId: number, topicName: string) => { - getTopicMetaData(clusterId, topicName).then(this.setTopicDetail); - } -} - -export const topic = new Topic(); diff --git a/console/src/store/users.ts b/console/src/store/users.ts deleted file mode 100644 index 0a74bd39..00000000 --- a/console/src/store/users.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { observable, action } from 'mobx'; -import { getUsers } from 'lib/api'; - -export interface IUserDetail { - password: number; - role: number; - username: string; -} - -export class Users { - public roleMap = ['普通用户', '运维人员', '管理员']; - public filterRole = this.roleMap.map(i => ({ text: i, value: i })); - - @observable - public userData: IUserDetail[] = []; - - @action.bound - public setUserData(data: []) { - this.userData = data.map((d: any) => { - d.roleName = this.roleMap[d.role]; - return d; - }); - } - - public mapRole(role: number) { - return this.roleMap[role]; - } - - public getUsers() { - getUsers().then(this.setUserData); - } -} - -export const users = new Users(); diff --git a/console/src/types/base-type.ts b/console/src/types/base-type.ts deleted file mode 100644 index c9589318..00000000 --- a/console/src/types/base-type.ts +++ /dev/null @@ -1,218 +0,0 @@ -export interface INewCluster { - alarmFlag: number; - bootstrapServers: string; - clusterId: number; - clusterName: string; - kafkaVersion: string; - saslJaasConfig: string; - saslMechanism: string; - securityProtocol: string; - zookeeper: string; -} - -export interface IClusterData { - bootstrapServers: string; - brokerNum: number; - clusterId: number; - clusterName: string; - controllerId: number; - consumerGroupNum: number; - gmtCreate: string; - gmtModify: string; - kafkaVersion: string; - regionNum: number; - status: number; - topicNum: number; - zookeeper: string; - alarmFlag: number; - saslJaasConfig: string; - saslMechanism: string; - securityProtocol: string; -} - -export interface ISeriesOption { - name: string; - type: string; - data: number[]; -} - -export interface IClusterMetrics { - gmtCreate: number; - bytesInPerSec: number; - bytesOutPerSec: number; - bytesRejectedPerSec: number; - messagesInPerSec: number; -} - -export interface IBrokerMetrics { - requestHandlerIdlPercent: number; - networkProcessorIdlPercent: number; - requestQueueSize: number; - responseQueueSize: number; - logFlushTime: number; - failFetchRequest: number; - failProduceRequest: number; - totalTimeProduceMean: number; - totalTimeProduce99Th: number; - totalTimeFetchConsumerMean: number; - totalTimeFetchConsumer99Th: number; - gmtCreate: number; -} - -export interface IValueLabel { - value: string; - label: string; -} - -export type IOptionType = 'byteIn/byteOut' | 'byteRejected' | 'messageIn' | 'messageIn/totalProduceRequests'; - -export interface ITaskDetail { - clusterId: number; - operator: number; - throttle: number; - topicName: string; - brokerIdList: number[]; -} - -interface IBase { - clusterId: number; - clusterName: string; - topicName: string; - principals: string; - description: string; - brokerIdList: string[]; - partitionNum: number; -} - -export interface IBaseOrder extends IBase { - peakBytesInPerSec: number; - orderId: number; - gmtModify: number; - gmtCreate: number; - orderStatus: number; - approver: string; - approvalOpinions: string; - applicant: string; - predictBytesIn: number; - realBytesIn: number; - regionBrokerIdList: any[]; - regionNameList: string[]; - statusStr?: string; - replicaNum?: number; - retentionTime?: number; - peakBytesIn?: number; - regions?: string; - brokers?: string; -} - -export interface ITopic extends IBase { - brokerNum: number; - byteIn: number; - byteOut: number; - favorite: boolean; - messageIn: number; - produceRequest: number; - replicaNum: number; - updateTime: number; - principalList: string[]; - properties: string; - regionIdList: number[]; - retentionTime: number; - peakBytesIn: number; - key?: number; -} - -export interface IFiler { - text: string; - value: string; -} - -export interface IDilation { - brokerIdList: number[]; - clusterId: number; - partitionNum: number; - regionIdList: number[]; - topicName: string; -} - -export interface IAlarmBase { - alarmName: string; - id?: number; - strategyExpressionList: IExpressionList[]; - strategyFilterList: IStrategyFilter[]; - strategyActionList: IActionList[]; - principalList: string[]; - status: number; -} - -export interface IExpressionList { - metric: string; - opt: string; - threshold: number; - duration: number; -} -export interface IStrategyFilter { - key: string | string[]; - value: string; -} - -export interface IActionList { - actionWay: string; - actionTag: string; -} -export interface ITaskBase { - taskId: number; - clusterId?: number; - topicName?: string; - status?: number; - throttle?: number; - partitionIdList?: string[]; - brokerIdList?: number[]; - description?: string; - action: string; -} - -export interface IRebalance { - brokerId: number; - clusterId: number; - dimension: number; -} - -export interface IOrderTopic { - orderId: number; - orderStatus: number; - retentionTime: number; - regionIdList: number[]; - brokerIdList: number[]; - approvalOpinions: string; - partitionNum: number; - replicaNum: number; -} - -export interface IUser { - password: string; - role: string; - username: string; - oldPassword: string; -} - -export interface ISample { - maxMsgNum: number; - offset: number; - partitionId: number; - clusterId: number; - topicName: string; -} - -export interface IDeleteTopic { - clusterId: number; - topicNameList: string[]; -} - -export interface IOffset { - clusterId: number; - consumerGroup: string; - location: string; - offsetList?: []; - topicName: string; -} diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/AlarmRuleDao.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/AlarmRuleDao.java deleted file mode 100644 index 4f98264e..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/AlarmRuleDao.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao; - -import com.xiaojukeji.kafka.manager.common.entity.po.AlarmRuleDO; - -import java.util.List; - -public interface AlarmRuleDao { - int insert(AlarmRuleDO alarmRuleDO); - - int deleteById(Long id); - - int updateById(AlarmRuleDO alarmRuleDO); - - AlarmRuleDO getById(Long id); - - List listAll(); -} \ No newline at end of file diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/MigrationTaskDao.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/MigrationTaskDao.java deleted file mode 100644 index 692c38cc..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/MigrationTaskDao.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao; - -import com.xiaojukeji.kafka.manager.common.entity.po.MigrationTaskDO; - -import java.util.List; - -/** - * migrate topic task dao - * @author zengqiao_cn@163.com - * @date 19/4/16 - */ -public interface MigrationTaskDao { - - /** - * 增加一个迁移任务 - */ - int addMigrationTask(MigrationTaskDO migrationTaskDO); - - /** - * 查询迁移任务 - */ - MigrationTaskDO getById(Long id); - - /** - * 查询所有的迁移任务 - */ - List listAll(); - - /** - * 查询所有的迁移任务 - */ - List getByStatus(Integer status); - - /** - * 修改任务 - */ - int updateById(Long id, Integer status, Long throttle); -} diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OperationHistoryDao.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OperationHistoryDao.java deleted file mode 100644 index fd127256..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OperationHistoryDao.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao; - -import com.xiaojukeji.kafka.manager.common.entity.po.OperationHistoryDO; - -/** - * @author arthur - * @date 2017/7/20. - */ -public interface OperationHistoryDao { - int insert(OperationHistoryDO operationHistoryDO); -} diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OrderPartitionDao.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OrderPartitionDao.java deleted file mode 100644 index 335c207b..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OrderPartitionDao.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao; - -import com.xiaojukeji.kafka.manager.common.entity.po.OrderPartitionDO; - -import java.util.List; - -public interface OrderPartitionDao { - int insert(OrderPartitionDO orderPartitionDO); - - int deleteById(Long id); - - int updateById(OrderPartitionDO orderPartitionDO); - - OrderPartitionDO getById(Long id); - - List list(); -} diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OrderTopicDao.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OrderTopicDao.java deleted file mode 100644 index 61b5e1c0..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/OrderTopicDao.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao; - -import com.xiaojukeji.kafka.manager.common.entity.po.OrderTopicDO; - -import java.util.List; - -public interface OrderTopicDao { - int insert(OrderTopicDO orderTopicDO); - - int deleteById(Long id); - - int updateById(OrderTopicDO orderTopicDO); - - OrderTopicDO getById(Long id); - - List list(); - - List getByUsername(String username); -} \ No newline at end of file diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicFavoriteDao.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicFavoriteDao.java deleted file mode 100644 index 8810364d..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/TopicFavoriteDao.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao; - -import com.xiaojukeji.kafka.manager.common.entity.po.TopicFavoriteDO; - -import java.util.List; - -public interface TopicFavoriteDao { - int batchAdd(List topicFavoriteDOList); - - Boolean batchDelete(List idList); - - List getByUserName(String username); - - List getByUserNameAndClusterId(String username, Long clusterId); -} \ No newline at end of file diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/AlarmRuleDaoImpl.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/AlarmRuleDaoImpl.java deleted file mode 100644 index d7fb6332..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/AlarmRuleDaoImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao.impl; - -import com.xiaojukeji.kafka.manager.common.entity.po.AlarmRuleDO; -import com.xiaojukeji.kafka.manager.common.entity.po.query.AlarmRuleQueryOption; -import com.xiaojukeji.kafka.manager.dao.AlarmRuleDao; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -import java.util.List; - -/** - * @author zengqiao - * @date 19/6/23 - */ -@Repository("alarmRuleDao") -public class AlarmRuleDaoImpl implements AlarmRuleDao { - @Autowired - private SqlSessionTemplate sqlSession; - - public void setSqlSession(SqlSessionTemplate sqlSession) { - this.sqlSession = sqlSession; - } - - @Override - public int insert(AlarmRuleDO alarmRuleDO) { - return sqlSession.insert("AlarmRuleDao.insert", alarmRuleDO); - } - - @Override - public int deleteById(Long id) { - return sqlSession.delete("AlarmRuleDao.deleteById", id); - } - - @Override - public int updateById(AlarmRuleDO alarmRuleDO) { - return sqlSession.update("AlarmRuleDao.updateById", alarmRuleDO); - } - - @Override - public AlarmRuleDO getById(Long id) { - AlarmRuleQueryOption alarmRuleQueryOption = new AlarmRuleQueryOption(); - alarmRuleQueryOption.setId(id); - List alarmRuleDOList = sqlSession.selectList("AlarmRuleDao.getByOption", alarmRuleQueryOption); - if (alarmRuleDOList == null || alarmRuleDOList.isEmpty()) { - return null; - } - return alarmRuleDOList.get(0); - } - - @Override - public List listAll() { - return sqlSession.selectList("AlarmRuleDao.getByOption", new AlarmRuleQueryOption()); - } -} \ No newline at end of file diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/KafkaManagerProperties.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/KafkaManagerProperties.java deleted file mode 100644 index d762c4ce..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/KafkaManagerProperties.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao.impl; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; - -@Component -@ConfigurationProperties("spring.datasource.kafka-manager") -public class KafkaManagerProperties { - private String jdbcUrl; - - public String getJdbcUrl() { - return jdbcUrl; - } - - public void setJdbcUrl(String jdbcUrl) { - this.jdbcUrl = jdbcUrl; - } - - public boolean hasPG() { - return jdbcUrl.startsWith("jdbc:postgres"); - } -} diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/MigrationTaskDaoImpl.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/MigrationTaskDaoImpl.java deleted file mode 100644 index a537c7ae..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/MigrationTaskDaoImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao.impl; - -import com.xiaojukeji.kafka.manager.common.entity.po.MigrationTaskDO; -import com.xiaojukeji.kafka.manager.dao.MigrationTaskDao; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * migrate topic task dao - * @author zengqiao_cn@163.com - * @date 19/4/16 - */ -@Repository("migrationTaskDao") -public class MigrationTaskDaoImpl implements MigrationTaskDao { - @Autowired - private SqlSessionTemplate sqlSession; - - public void setSqlSession(SqlSessionTemplate sqlSession) { - this.sqlSession = sqlSession; - } - - @Override - public int addMigrationTask(MigrationTaskDO migrationTaskDO) { - return sqlSession.insert("MigrationTaskDao.addMigrationTask", migrationTaskDO); - } - - @Override - public MigrationTaskDO getById(Long id) { - return sqlSession.selectOne("MigrationTaskDao.getById", id); - } - - @Override - public List listAll() { - return sqlSession.selectList("MigrationTaskDao.listAll"); - } - - @Override - public List getByStatus(Integer status) { - return sqlSession.selectList("MigrationTaskDao.getByStatus", status); - } - - @Override - public int updateById(Long id, Integer status, Long throttle) { - Map params = new HashMap<>(); - params.put("id", id); - params.put("status", status); - params.put("throttle", throttle); - return sqlSession.update("MigrationTaskDao.updateById", params); - } -} diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OperationHistoryDaoImpl.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OperationHistoryDaoImpl.java deleted file mode 100644 index 23015526..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OperationHistoryDaoImpl.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao.impl; - -import com.xiaojukeji.kafka.manager.common.entity.po.OperationHistoryDO; -import com.xiaojukeji.kafka.manager.dao.OperationHistoryDao; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -/** - * @author arthur - * @date 2017/7/20. - */ -@Repository("operationHistoryDao") -public class OperationHistoryDaoImpl implements OperationHistoryDao { - @Autowired - private SqlSessionTemplate sqlSession; - - public void setSqlSession(SqlSessionTemplate sqlSession) { - this.sqlSession = sqlSession; - } - - @Override - public int insert(OperationHistoryDO operationHistoryDO) { - return sqlSession.insert("OperationHistoryDao.insert", operationHistoryDO); - } -} diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OrderPartitionDaoImpl.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OrderPartitionDaoImpl.java deleted file mode 100644 index 3a3877af..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OrderPartitionDaoImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao.impl; - -import com.xiaojukeji.kafka.manager.common.entity.po.OrderPartitionDO; -import com.xiaojukeji.kafka.manager.dao.OrderPartitionDao; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -import java.util.List; - -/** - * @author zengqiao - * @date 19/6/21 - */ -@Repository("orderPartitionDao") -public class OrderPartitionDaoImpl implements OrderPartitionDao { - @Autowired - private SqlSessionTemplate sqlSession; - - public void setSqlSession(SqlSessionTemplate sqlSession) { - this.sqlSession = sqlSession; - } - - @Override - public int insert(OrderPartitionDO orderPartitionDO) { - return sqlSession.insert("OrderPartitionDao.insert", orderPartitionDO); - } - - @Override - public int deleteById(Long id) { - return sqlSession.delete("OrderPartitionDao.deleteById", id); - } - - @Override - public int updateById(OrderPartitionDO orderPartitionDO) { - return sqlSession.update("OrderPartitionDao.updateById", orderPartitionDO); - } - - @Override - public OrderPartitionDO getById(Long id) { - return sqlSession.selectOne("OrderPartitionDao.getById", id); - } - - @Override - public List list() { - return sqlSession.selectList("OrderPartitionDao.list"); - } -} \ No newline at end of file diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OrderTopicDaoImpl.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OrderTopicDaoImpl.java deleted file mode 100644 index dacd3891..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/OrderTopicDaoImpl.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao.impl; - -import com.xiaojukeji.kafka.manager.common.entity.po.OrderTopicDO; -import com.xiaojukeji.kafka.manager.dao.OrderTopicDao; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -import java.util.List; - -/** - * @author zengqiao - * @date 19/6/21 - */ -@Repository("orderTopicDao") -public class OrderTopicDaoImpl implements OrderTopicDao { - @Autowired - private SqlSessionTemplate sqlSession; - - public void setSqlSession(SqlSessionTemplate sqlSession) { - this.sqlSession = sqlSession; - } - - @Override - public int insert(OrderTopicDO orderTopicDO) { - return sqlSession.insert("OrderTopicDao.insert", orderTopicDO); - } - - @Override - public int deleteById(Long id) { - return sqlSession.delete("OrderTopicDao.deleteById", id); - } - - @Override - public int updateById(OrderTopicDO orderTopicDO) { - return sqlSession.update("OrderTopicDao.updateById", orderTopicDO); - } - - @Override - public OrderTopicDO getById(Long id) { - return sqlSession.selectOne("OrderTopicDao.getById", id); - } - - @Override - public List list() { - return sqlSession.selectList("OrderTopicDao.list"); - } - - @Override - public List getByUsername(String username) { - return sqlSession.selectList("OrderTopicDao.getByUsername", username); - } -} \ No newline at end of file diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicDaoImpl.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicDaoImpl.java deleted file mode 100644 index 7c5bac5f..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicDaoImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao.impl; - -import com.xiaojukeji.kafka.manager.common.entity.po.TopicDO; -import com.xiaojukeji.kafka.manager.dao.TopicDao; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author zengqiao - * @date 19/7/12 - */ -@Repository("TopicDao") -public class TopicDaoImpl implements TopicDao { - @Autowired - private SqlSessionTemplate sqlSession; - - @Autowired - private KafkaManagerProperties kafkaManagerProperties; - - public void setSqlSession(SqlSessionTemplate sqlSession) { - this.sqlSession = sqlSession; - } - - @Override - public int replace(TopicDO topicDO) { - if (kafkaManagerProperties.hasPG()) { - return sqlSession.insert("TopicDao.replaceOnPG", topicDO); - } - return sqlSession.insert("TopicDao.replace", topicDO); - } - - @Override - public int deleteById(Long id) { - return sqlSession.delete("TopicDao.deleteById", id); - } - - @Override - public int deleteByName(Long clusterId, String topicName) { - Map params = new HashMap<>(); - params.put("clusterId", clusterId); - params.put("topicName", topicName); - return sqlSession.delete("TopicDao.deleteByName", params); - } - - @Override - public TopicDO getByTopicName(Long clusterId, String topicName) { - Map params = new HashMap<>(); - params.put("clusterId", clusterId); - params.put("topicName", topicName); - return sqlSession.selectOne("TopicDao.getByTopicName", params); - } - - @Override - public List getByClusterId(Long clusterId) { - return sqlSession.selectList("TopicDao.getByClusterId", clusterId); - } - - @Override - public List list() { - return sqlSession.selectList("TopicDao.list"); - } -} \ No newline at end of file diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicFavoriteDaoImpl.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicFavoriteDaoImpl.java deleted file mode 100644 index f8d0c7fc..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicFavoriteDaoImpl.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao.impl; - -import com.xiaojukeji.kafka.manager.common.entity.po.TopicFavoriteDO; -import com.xiaojukeji.kafka.manager.dao.TopicFavoriteDao; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.support.TransactionCallback; -import org.springframework.transaction.support.TransactionTemplate; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author zengqiao - * @date 19/6/23 - */ -@Repository("topicFavoriteDao") -public class TopicFavoriteDaoImpl implements TopicFavoriteDao { - @Autowired - private SqlSessionTemplate sqlSession; - - @Autowired - private TransactionTemplate transactionTemplate; - - @Autowired - private KafkaManagerProperties kafkaManagerProperties; - - public void setSqlSession(SqlSessionTemplate sqlSession) { - this.sqlSession = sqlSession; - } - - @Override - public int batchAdd(List topicFavoriteDOList) { - if (kafkaManagerProperties.hasPG()) { - return sqlSession.insert("TopicFavoriteDao.batchAddOnPG", topicFavoriteDOList); - } - return sqlSession.insert("TopicFavoriteDao.batchAdd", topicFavoriteDOList); - } - - @Override - public Boolean batchDelete(List idList) { - return transactionTemplate.execute(new TransactionCallback() { - @Override - public Boolean doInTransaction(TransactionStatus status) { - if (idList == null) { - return Boolean.TRUE; - } - for (Long id: idList) { - try { - if (deleteById(id) <= 0) { - status.setRollbackOnly(); - return Boolean.FALSE; - } - } catch (Throwable t) { - status.setRollbackOnly(); - return Boolean.FALSE; - } - } - return Boolean.TRUE; - } - }); - } - - private int deleteById(Long id) { - return sqlSession.delete("TopicFavoriteDao.deleteById", id); - } - - @Override - public List getByUserName(String username) { - return sqlSession.selectList("TopicFavoriteDao.getByUserName", username); - } - - @Override - public List getByUserNameAndClusterId(String username, Long clusterId) { - Map params = new HashMap<>(); - params.put("username", username); - params.put("clusterId", clusterId); - return sqlSession.selectList("TopicFavoriteDao.getByUserNameAndClusterId", params); - } - -} \ No newline at end of file diff --git a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicMetricsDaoImpl.java b/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicMetricsDaoImpl.java deleted file mode 100644 index 8585ced5..00000000 --- a/dao/src/main/java/com/xiaojukeji/kafka/manager/dao/impl/TopicMetricsDaoImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.xiaojukeji.kafka.manager.dao.impl; - -import com.xiaojukeji.kafka.manager.common.entity.metrics.TopicMetrics; -import com.xiaojukeji.kafka.manager.dao.TopicMetricsDao; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -import java.util.*; - -/** - * dao实现 - * @author tukun - * @date 2015/11/11. - */ -@Repository("topicMetricDao") -public class TopicMetricsDaoImpl implements TopicMetricsDao { - @Autowired - private SqlSessionTemplate sqlSession; - - public void setSqlSession(SqlSessionTemplate sqlSession) { - this.sqlSession = sqlSession; - } - - @Override - public int batchAdd(List topicMetricsList) { - return sqlSession.insert("TopicMetricsDao.batchAdd", topicMetricsList); - } - - @Override - public List getTopicMetricsByInterval(Long clusterId, - String topicName, - Date startTime, - Date endTime) { - Map map = new HashMap<>(); - map.put("clusterId", clusterId); - map.put("topicName", topicName); - map.put("startTime", startTime); - map.put("endTime", endTime); - return sqlSession.selectList("TopicMetricsDao.getTopicMetricsByInterval", map); - } - - @Override - public int deleteBeforeTime(Date endTime) { - return sqlSession.delete("TopicMetricsDao.deleteBeforeTime", endTime); - } -} diff --git a/dao/src/main/resources/mapper/AccountDao.xml b/dao/src/main/resources/mapper/AccountDao.xml deleted file mode 100644 index feed2727..00000000 --- a/dao/src/main/resources/mapper/AccountDao.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - DELETE FROM account WHERE username = #{username} - - - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/AlarmRuleDao.xml b/dao/src/main/resources/mapper/AlarmRuleDao.xml deleted file mode 100644 index a2e038e2..00000000 --- a/dao/src/main/resources/mapper/AlarmRuleDao.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/BrokerDao.xml b/dao/src/main/resources/mapper/BrokerDao.xml deleted file mode 100644 index 50af2ef1..00000000 --- a/dao/src/main/resources/mapper/BrokerDao.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - REPLACE broker - (cluster_id, broker_id, host, port, timestamp, status) - VALUES - (#{clusterId}, #{brokerId}, #{host}, #{port}, #{timestamp}, #{status}) - - - - insert into broker - (cluster_id, broker_id, host, port, timestamp, status) - values (#{clusterId}, #{brokerId}, #{host}, #{port}, #{timestamp}, #{status}) - on conflict (cluster_id, broker_id) do update set host = excluded.host, - port = excluded.port, - timestamp = excluded.timestamp, - status = excluded.status - - - - DELETE FROM broker WHERE cluster_id = #{clusterId} AND broker_id = #{brokerId} - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/BrokerMetricsDao.xml b/dao/src/main/resources/mapper/BrokerMetricsDao.xml deleted file mode 100644 index b932a010..00000000 --- a/dao/src/main/resources/mapper/BrokerMetricsDao.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INSERT INTO broker_metrics (cluster_id, broker_id, bytes_in, bytes_out, messages_in, bytes_rejected, fail_fetch_request, fail_produce_request, fetch_consumer_request, produce_request, request_handler_idl_percent, network_processor_idl_percent, request_queue_size, response_queue_size, log_flush_time, total_time_produce_mean, total_time_produce_99th, total_time_fetch_consumer_mean, total_time_fetch_consumer_99th, gmt_create) - VALUES - - (#{BrokerMetrics.clusterId}, #{BrokerMetrics.brokerId}, #{BrokerMetrics.bytesInPerSec}, #{BrokerMetrics.bytesOutPerSec}, #{BrokerMetrics.messagesInPerSec}, #{BrokerMetrics.bytesRejectedPerSec}, #{BrokerMetrics.failFetchRequestPerSec}, #{BrokerMetrics.failProduceRequestPerSec}, #{BrokerMetrics.fetchConsumerRequestPerSec}, #{BrokerMetrics.produceRequestPerSec}, #{BrokerMetrics.requestHandlerAvgIdlePercent}, #{BrokerMetrics.networkProcessorAvgIdlePercent}, #{BrokerMetrics.requestQueueSize}, #{BrokerMetrics.responseQueueSize}, #{BrokerMetrics.logFlushRateAndTimeMs}, #{BrokerMetrics.totalTimeProduceMean}, #{BrokerMetrics.totalTimeProduce99Th}, #{BrokerMetrics.totalTimeFetchConsumerMean}, #{BrokerMetrics.totalTimeFetchConsumer99Th}, now()) - - - - - - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/ClusterDao.xml b/dao/src/main/resources/mapper/ClusterDao.xml deleted file mode 100644 index 153dd00b..00000000 --- a/dao/src/main/resources/mapper/ClusterDao.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - INSERT INTO cluster ( - cluster_name, zookeeper, bootstrap_servers, kafka_version, alarm_flag, - security_protocol, sasl_mechanism, sasl_jaas_config - ) VALUES ( - #{clusterName}, #{zookeeper}, #{bootstrapServers}, #{kafkaVersion}, #{alarmFlag}, - #{securityProtocol}, #{saslMechanism}, #{saslJaasConfig} - ) - - - - DELETE FROM cluster id = #{id} - - - - UPDATE cluster SET - cluster_name=#{clusterName}, - zookeeper=#{zookeeper}, - bootstrap_servers=#{bootstrapServers}, - kafka_version=#{kafkaVersion}, - alarm_flag=#{alarmFlag}, - security_protocol=#{securityProtocol}, - sasl_mechanism=#{saslMechanism}, - sasl_jaas_config=#{saslJaasConfig} - WHERE id = #{id} - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/ClusterMetricsDao.xml b/dao/src/main/resources/mapper/ClusterMetricsDao.xml deleted file mode 100644 index 6b726639..00000000 --- a/dao/src/main/resources/mapper/ClusterMetricsDao.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - INSERT INTO cluster_metrics (cluster_id, topic_num, partition_num, broker_num, bytes_in, bytes_out, bytes_rejected, messages_in, gmt_create) - VALUES - - (#{ClusterMetricsDO.clusterId}, #{ClusterMetricsDO.topicNum}, #{ClusterMetricsDO.partitionNum}, #{ClusterMetricsDO.brokerNum}, #{ClusterMetricsDO.bytesInPerSec}, #{ClusterMetricsDO.bytesOutPerSec}, #{ClusterMetricsDO.bytesRejectedPerSec}, #{ClusterMetricsDO.messagesInPerSec}, now()) - - - - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/MigrationTaskDao.xml b/dao/src/main/resources/mapper/MigrationTaskDao.xml deleted file mode 100644 index d2f9ce24..00000000 --- a/dao/src/main/resources/mapper/MigrationTaskDao.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - SELECT LAST_INSERT_ID() - - - - - - - - - - - - UPDATE migration_task - SET - real_throttle=#{throttle}, - status=#{status} - WHERE id=#{id} - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/OperationHistoryDao.xml b/dao/src/main/resources/mapper/OperationHistoryDao.xml deleted file mode 100644 index e9870a5c..00000000 --- a/dao/src/main/resources/mapper/OperationHistoryDao.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - INSERT INTO operation_history ( - cluster_id, topic_name, operator, operation) - VALUES ( - #{clusterId}, #{topicName}, #{operator}, #{operation} - ) - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/OrderPartitionDao.xml b/dao/src/main/resources/mapper/OrderPartitionDao.xml deleted file mode 100644 index 8214865b..00000000 --- a/dao/src/main/resources/mapper/OrderPartitionDao.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - INSERT INTO order_partition ( - cluster_id, cluster_name, topic_name, applicant, - peak_bytes_in, description, order_status) - VALUES ( - #{clusterId}, #{clusterName}, #{topicName}, #{applicant}, - #{peakBytesIn}, #{description}, #{orderStatus} - ) - - - - DELETE FROM order_partition WHERE id=#{id} - - - - UPDATE order_partition SET - cluster_id=#{clusterId}, - cluster_name=#{clusterName}, - topic_name=#{topicName}, - applicant=#{applicant}, - - - partition_num=#{partitionNum}, - - - - - broker_list=#{brokerList}, - - - peak_bytes_in=#{peakBytesIn}, - description=#{description}, - order_status=#{orderStatus}, - approver=#{approver}, - opinion=#{opinion} - WHERE id=#{id} - - - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/OrderTopicDao.xml b/dao/src/main/resources/mapper/OrderTopicDao.xml deleted file mode 100644 index 32e50032..00000000 --- a/dao/src/main/resources/mapper/OrderTopicDao.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - INSERT INTO order_topic ( - cluster_id, cluster_name, topic_name, - retention_time, partition_num, replica_num, - applicant, peak_bytes_in, description, principals - ) - VALUES ( - #{clusterId}, #{clusterName}, #{topicName}, - #{retentionTime}, #{partitionNum}, #{replicaNum}, - #{applicant}, #{peakBytesIn}, #{description}, #{principals} - ) - - - - DELETE FROM order_topic WHERE id=#{id} - - - - UPDATE order_topic SET - cluster_id=#{clusterId}, - cluster_name=#{clusterName}, - topic_name=#{topicName}, - retention_time=#{retentionTime}, - partition_num=#{partitionNum}, - replica_num=#{replicaNum}, - regions=#{regions}, - brokers=#{brokers}, - applicant=#{applicant}, - principals=#{principals}, - peak_bytes_in=#{peakBytesIn}, - description=#{description}, - order_status=#{orderStatus}, - approver=#{approver}, - opinion=#{opinion} - WHERE id=#{id} - - - - - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/RegionDao.xml b/dao/src/main/resources/mapper/RegionDao.xml deleted file mode 100644 index 7b1c7daa..00000000 --- a/dao/src/main/resources/mapper/RegionDao.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - REPLACE region - (region_name, cluster_id, broker_list, description, operator) - VALUES - (#{regionName}, #{clusterId}, #{brokerList}, #{description}, #{operator}) - - - - insert into region - (region_name, cluster_id, broker_list, description, operator) - values (#{regionName}, #{clusterId}, #{brokerList}, #{description}, #{operator}) - on conflict (region_name, cluster_id) do update set broker_list = excluded.broker_list, - description = excluded.description, - operator = excluded.operator - - - - DELETE FROM region WHERE id = #{id} - - - - UPDATE region SET - region_name=#{regionName}, - cluster_id=#{clusterId}, - broker_list=#{brokerList}, - description=#{description}, - operator=#{operator}, - status=#{status}, - level=#{level} - WHERE id=#{id} - - - - - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/TopicDao.xml b/dao/src/main/resources/mapper/TopicDao.xml deleted file mode 100644 index b078d4cf..00000000 --- a/dao/src/main/resources/mapper/TopicDao.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - REPLACE topic - (cluster_id, topic_name, principals, description, status) - VALUES - (#{clusterId}, #{topicName}, #{principals}, #{description}, #{status}) - - - - insert into topic - (cluster_id, topic_name, principals, description, status) - values (#{clusterId}, #{topicName}, #{principals}, #{description}, #{status}) - on conflict (cluster_id, topic_name) do update set principals = excluded.principals, - description = excluded.description, - status = excluded.status - - - - DELETE FROM topic WHERE id = #{id} - - - - DELETE FROM topic WHERE cluster_id = #{clusterId} and topic_name = #{topicName} - - - - - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/TopicFavoriteDao.xml b/dao/src/main/resources/mapper/TopicFavoriteDao.xml deleted file mode 100644 index 218a714c..00000000 --- a/dao/src/main/resources/mapper/TopicFavoriteDao.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - REPLACE topic_favorite (cluster_id, topic_name, username) - VALUES - - (#{TopicFavoriteDO.clusterId}, #{TopicFavoriteDO.topicName}, #{TopicFavoriteDO.username}) - - - - - insert into topic_favorite (cluster_id, topic_name, username) - values - - (#{TopicFavoriteDO.clusterId}, #{TopicFavoriteDO.topicName}, #{TopicFavoriteDO.username}) - - on conflict (cluster_id, topic_name, username) do update set gmt_modify = now(); - - - - DELETE FROM topic_favorite WHERE id=#{id} - - - - - - \ No newline at end of file diff --git a/dao/src/main/resources/mapper/TopicMetricsDao.xml b/dao/src/main/resources/mapper/TopicMetricsDao.xml deleted file mode 100644 index ece8f826..00000000 --- a/dao/src/main/resources/mapper/TopicMetricsDao.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - INSERT INTO topic_metrics - (cluster_id, topic_name, messages_in, bytes_in, bytes_out, bytes_rejected, total_produce_requests, gmt_create) - values - - (#{TopicMetrics.clusterId}, #{TopicMetrics.topicName}, #{TopicMetrics.messagesInPerSec}, #{TopicMetrics.bytesInPerSec}, #{TopicMetrics.bytesOutPerSec}, #{TopicMetrics.bytesRejectedPerSec}, #{TopicMetrics.totalProduceRequestsPerSec}, now()) - - - - - - - - - \ No newline at end of file diff --git a/dao/src/main/resources/spring-dao.xml b/dao/src/main/resources/spring-dao.xml deleted file mode 100644 index 8bb03753..00000000 --- a/dao/src/main/resources/spring-dao.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/assets/images/kafka_manager_cn_guide/admin_add_cluster.jpg b/doc/assets/images/kafka_manager_cn_guide/admin_add_cluster.jpg deleted file mode 100644 index 20acd79cdaaec8d8cc4fc5cc479d3df2416a7a41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47116 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 N6d9a}n-JUY{vWvfD31UD diff --git a/doc/assets/images/kafka_manager_cn_guide/admin_cluster_broker_detail.jpg b/doc/assets/images/kafka_manager_cn_guide/admin_cluster_broker_detail.jpg deleted file mode 100644 index 8b69f47b03342a61eddb8bab400ec4045ac31323..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66049 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 U1_urnyd1e1c&ASxW3>K%0sH>SwEzGB diff --git a/doc/assets/images/kafka_manager_cn_guide/admin_cluster_details.jpg b/doc/assets/images/kafka_manager_cn_guide/admin_cluster_details.jpg deleted file mode 100644 index 8b1f5025218605720a445ec6276bc0d07479056b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55607 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 aoO2l@>sBSMfV)1Q=~tjVEpQQE-u(~A)wies diff --git a/doc/assets/images/kafka_manager_cn_guide/admin_order.jpg b/doc/assets/images/kafka_manager_cn_guide/admin_order.jpg deleted file mode 100644 index ad857e3b75b6b3aade3abd3d08f8fd4e2ceead26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48364 zcmeFY1y~es*DyZI64G7L(%s!4B_e{9q;yG0gTM-kGzdrt(o&L2hoE#R(y25E(ntyH z{s)Yo`qcY;@ALoSy551EIeX9P`eOj~y zP#Yuw4-f`KP0d}MWv^eqddBm|^_>6D)Bec0?!X}D8Lyws|1|*L!qU|oH2yk>Zf4xWxARioO5aw~Tuyq9C3=ozww=uN<;TaI-aBy$}VO%T_W->92zT0o7JY{&Y}}Q#LHG=R&D>S~ECNXYu(K^pFROwu=u0FL zcYAHw?=YXK3kaR#BVDs~Q_=bko4Gh?e&>(m;duMnS$v%F39+$M`2nX{x+>fN+d&92g@ytdL2TJDP3PR`np0)l0ju-79_JMHz!E6I0r?`b6tXz- zRq!kWe)y0@kVSvc(c=El6IB8AGO9AFA}Z^T7Qh_T`ZoA+0c`(Hn<{wE612_*JUjld z;V*tDODO#)b11_oGbrPL4zO^}<-4UOwt+4`H2BF`4VVGBee;SX=rKoN5&v_uwJ8njIiZ2jTAGp*f!>h_l}fB5|e-kH|4zu5S_9fu7^ z@VgdfKdb_K@`oq>=2Y{lD7icfj;|1OTtzo4dPse8WRNyPyCV04|sr!Yfd=3W&<^wf?}1@p5{!*S z;4`oV>;uOT2m}p+4IzY(Lueq35OxS3L_EOEL6NYKh>)m|n2@-UM37{WRFSlhjF7C6?jZRf zJwS>=NkNZ^ciUn3P3TTBv3jiCsYI~4^@ZiL#?1LP=9C`Gy$3g zErHg7eLV=Bfv!Q1kWrBdk!g`R!T3~0)9opLwkt!1g!|I32gvv5$*5-<^`Gyd>0fi=wEQW5O^Ws z!t)D_7X~gYUpPj`LuW)6Lsv()K=($EMt_E0hu(+2h<=QLkHL%~iJ^sIhY^60gi(Ug zhB1Y)i;0PO2~!kP1Jf4s9%d3|8D=NuEanjw0TvsUJeDDrJ604{9@cBDajaczY-}cM z8Ek!QH|!|v0_+y-kJyJegg9I{DmWH6Fq{;eDx3kF4P10wMqF83V_YBH1l)4mKHN1t zbUY?Jc|21*f4mgDTD(!bJ$yoZUVL?Y2mA>9=lEUtp9s(hm_wbH{EB#n1WLk0qC#?; zB%0(U$q30;QYuneQcKcM(h|}E(gQLIG8r;UvM{nzvSG5XW>fZ3?om-wDN#97J)vr$TB9bR zmZ7$zeoWm+y+T7sBSm9N^O&ZIW|fwhR+jcQZ4zxO?G_y+oid#}T_)W-y5mdCm$WYh zUMjuxfgXcigx-q&F?}=r76T1~8iOxGA;SbCI->}q4Pzo>2jc+~Gm|b;FjFvP9&cW}db1bJ@rJmZ<C3yND~+nBotH=3>It_JQWfaauF&KS`lUtz9sxr zcvOT)pk*1S2mCll$lcATfkja%vT zs>!NzSJ|$*T&+_>QoEuSr#5ws@tWhcYIQ(eMLkaa!*%BCcdplKplV##NYPl*^m=YyylH#0MjuUI zM?Y78&p^Q--eA#C(D0$*h!L}qmr7JR2 z*;BJEb9wVb^UoGC7LP4fEF~>tEtjn%tzxY{SxZ{SS+Ceg+a%bm*~;4{+iu$_+ojtb z*sI&;*&}Z2-Y#{x;Bd>K){(%`-m%q*+R4kQ-(Qa$O;=My@q( zMBr4X*PX>Z$bHsB$|J?&&{M~=+za2!(W}>+%{$b4*+rwcO?iUq$gq|x+l&gT}`Ta!tmtLlapkd|`%^1s6%B;#_%1X#a&GyJ%dZzQNBS$2sAopT!cSESLzh@rZMR5wb&pU_ zRj*)gyM>5S0KtJ%x5y>mC_Cg;uPKQFj0oGd4_8u(!ZVJz@^HvQI;0g(9le}2H0v%}SjpYI%iV7Y)(lS2ezmkI#T>Hy%>1%WtD zMIcU}f%Eop0C;`p+q&-z8x;=#GS1faK%WHpy|e4D2jVq=e*v_Od_rQ<4UdeDjZe(Z%`Yr2Eq_{B-QL;#vbTS5c=YwmE(mDn zkK>zVf7pc&+J%IS3`IsevkQXc34WmX$S8EYs06YaXr^}vFYyIjAd-v8eDMaIo?ml| z*vzFLgM>j~mT~*cv~$b;Yla2>FIo1}u)pk@1Sic%=LZxC35o)RLQzmrzytLHINL%+ zy?}Ay{J{8rV4WX0X9w=j0|7FDfIN_qk9@kTOT}APgw|hXDyq0njX|i@I4)-%d0F9(4?2FN%b?~NnY`MPc zhqj)c-lh(OO3wR^o#CvvWE^#$x|Ke8>(!i!&Zvm<+|T^E@wL&RW6Hz;wmDN)Gq&fP zl0;ve-WpHP+<;lHOz(asJ>6=WHNhA=Q8~<>Nf`>)N}KJt;gnBzt7SX{`!LY{ZQdLg zxoW~I(UxJD`j(_mBau0!ciC{Jw9+Ye>v8E{W+4EK1qqb-b@q;A^~oZoxI5^Wcc7FN zx0P1&Ucf8&Z~EH?x5=mD3NoHLjh!F>fvy*NY-xSOYHe`;XzLv@1hBR){li4Ib+zKdI6ipgcEy&|LS8_031e?kGZKL&wC6MVRkm+)+PIF;tC)zD2(O!r$D1)mHNzy-j9F08D@SP0eh6h))Xx%WrwtPRbr*JlJZ5!{7zg>IZZ^LQ*#+}E1 zjfVerR{WXM|E-+-qi4aeLL;8Pi;1#j+}J$9*q-j;`U18br#(%906L$PB7iZe&j>(4 zkQ9n|e|nO2Ps;i5VH9|5Slz&>Rwt#cv(S|eO|;{pQcS8U?hmOmtdwSo@xe>*dJ z{Eq&FeOF?0cA||rz)34cuzA&PYodbFIgvs3p-v=^@^#N;5oC48$NifO{}F)wm+BZF&NfgiXmR1{ijHL1O(A`2HD2?x3kQG1CAdFnR> z&s7euIc+d(z1Q1l9Xz@u&2;ruN9rSnT}+w}LG#R1?4Lj6k+l$>NQyC2n`{fgopkE> zX9o8*pKih0>yOpcQ%=~}7vkd#($KaVzaGDtCZZj%bYx6ZlX4cp?!p*D0A5H^mAC<# z^X)Vw#qKPR0yx(a-$~bABxsR7{PcBnc}h@JUMRxZVP{wR1g-Duntxu~)`J~ZRUQ>J z1!CG9)gEwLDvJTbVy2ke%5x@(YV8K_o zv;IMI#n$UhTSdNf!oeJlvz7QpE&0`BjeSKoJ2z>oYpR4Svr#M-k8UH8VdHvlt9PhD zn@M=5S0_*#JL}9plbT_3-HeQk^;@c8k0%I-TcDR{MY?Q_+F;(%R8AAs$dKqncGz-l zcwy*7m^#R3)JIhvyLigq|5WvAMeJfmbs9|kAWI?f)bJKnVMRdZI*dY!!NiMsh9;ts z{gAV`WaEn;(yq?n#0*Jg{9HA^oJ9*AZ#DT*V$^)G{CxTYg2SGD?_oGfq?W!^;cS-x zZgtYtKz_#3@rF%ipM;K&;|)HJo3hMdhaLMF+g$O-Y)acE3h%R}@tqt#He;hI;?Qp+ zUqAqM)xHe|b5*>m?2qQ%SZ=D*j;a;HdtTW23va{123uVeEa!}<@7f5=12!C$g+07^ zQ>)KCExH(soI4gHGd=1pp6J~x#(93QAF|aKbRue7>{ZpHNiyay}QY9TU|GT~-WP4XH{G!ao%x6wX-hjvzI2)?{2$(P1+Kb1Db-Zu}|Fn7v(ZA#yJ zx`Y7AmOXnS58q5CAba?vcbK4kYGhW&Ssn4oc}iecW@BH_XU?H-Z>LM=n?&M?S>NlS zH==z5|8Yq5Q97sB!}?=Z`$mRs-#U2t++Fd!#c63)TJXb4~hewr|?$UUca`z}N2{ z<9b6EKhG%F9ny#IPF_mCrM{L(df)wnfUIj~WAN-jW1_lyKao9SNp=E@&fSA2qj(%U z*xL$}v5}ciad|*nru_*{jJNvQqp=m{Y0&iTct2I&X%WmBK7Cwe>q)fo%HrM?s2EOA z8LE%Pt>M1=jQ}jj1pS0!t84RN?nlD@HMeXx`W-MQ%>qn!C0_NF`%kS;jjhCu1ga}% z-NRr3{>cgNOO60!$6xRe6?~*@ zdY{LkSxyRkvWyD!t&?qVb2vFvVzRCqPbil}TpK_h zGwH2~Tht7u#d_2cBZD>I&*7D)T~#qOvvs0o^L~OnctXXMb2T$0TQOFyFm~QvC1!_& zy~fJ@P(6QgRZQXSv*cU%RjO6*P#9d3m7c!TL^-6@#J)H+5MP@p)DdZ8 zLR2ZK`E}%-pA;Eubu-k zUPEM!!|NTD6%)qboMgqU<@k}*%F!DeyxK2q2kf3Yu-E(Q+h!yOw_+=H+#D_<>0-LC zrg?nu-0y9KJc%=^c9fWFl-Tg+Xo#9nL4h&jE`wOemYiRE^^RPT$Bs=UH893B6Hbs9FEAR1t zfumK+vDx@_-0ehaZX#afz6N-V5_3on=CGE+RzCnxI4dWhE@#CJ}bdf=4vZ4!i;UW{)ijf6%HM!Vd^ z`<2CXYkbElu0s?6qW>#TH-@l!>71`S%>_yo1_Lkb55bUo+NeCp_?IL6zsYN7aFGaP+h<&Q`+X+k5JOM78ck$xjtStx?y$yx!%b0Qf9u z5(BY)tV1R2d6IF_Kd`@LIdXI~(;!*u_!#NpER`2_6iswE&D%bc6JOI^vFc{KvQ%*r z=^{}@rnCL{SvJ`QxTAXiD5(iYkUqm#Q;n-N#x_48Xnp~=&ghzC$XuP%LowX_gYda+ zEMAq<)U50d%7LAM-YIj*{fLFpc`01WC(rnaZEBja3##u*Qm0kF*l*BIn$3BK zHak7qrS~<0n*Rza3QR9OgnzD&3O?x1w$&8TAUhi=E?<#`EoJK9AW`f>PKi9tu}Tlg zqIePz8rrEe=j>{Aqnv>bD!j-d5%mze}{v^Gj3prrLGjY>nvs%obS01aN)i z@fLlJp~PJ1Ka@O@KHG$A54$x$TRT!LSTON!bz>F1weGUzgb4Ba=sO*Ho47^!7CKAX z(R>46@@=d}oUN$TqQf+m%03KR2aA{b?VKErTnrCnb{cr$UzEy&LM5z2Hngz@+FqXH^iMFdvqx<(YGHsPU zI8mPs6}-!-D2>-8(8OnSIp4aLzf8K(#iQ^ReqgJMOoskN7?zZn9b90$GCgRIrN}&N zqkYchMsJ{H?St0K8qcEOcJa2DJnbLu->;7ay%EZ14fnLdQb{psAN}d*10IS-b1H zGDj(_^6gQhtIaKZzc@2*GnuxC`u)u*rJl%1Xa0y?S!TLB+q$nkeBLev`4xn#h7+YO zde0@WJ9C=vT4OqYqVovjuN^jwCuh#=Nc;>dcMP6$a6tfC+c=e;-cG(>GrhVMnRxBW z1aQ%7-o*6;7#v{K%iTi#5b<6TI|VjD^P0QZc+Bvv07*YrTGhLeQE8jH+9uUd9ps9g z2gePCE}w(MhZfwj)ejlP4omvl{pq$9mP!k58jfG9&#ZpPS0yy6)0tv^b+&D?{^>#u zg-2eOjE#vjbt8?PnE5I-*-++Crw~V)Y3vAV=BqkYg;;Wn=-Zi=e!*62Dj{Qq7r{O7 zhd%vMZ?g4Zw~Zb89kQz;tJ)Iv_E-cZs(XfB)n&Fz$-%;rA(=XZvvM zF}?k>ww`-yw!cIG)>D27o82+}nm3%Jz_$|!Dex%B$+Ksh9(;9rxcP^y}f_$5skujT3&|Dz>3g| z2}6COw@VG4JfRQ2KxE13DRoC^wwhp82;eIVHK@g#cu)ya6JGh26Ezkww{0DDom$wj z`PvI(7E^XDZM&ILhN5(#LIl7lWs{3D}4?_T1akG6V6#58YyBn#aLN^=%v?%%aA%I`x z%joTgZNm<2HpdYFJWM@UddtBc0d%lnQvY4akbfwbYiok#a_e%j?j<=P1Ggvc(?=Pa5 zj}(d@o2Y`1%W9f7UtD`_Gvc}5_yhq+Yrv+>!XepV@8BbY(#xyd$7>q51nhsoRk+t* zw7Krb4fme|ACpvl#6y9$Z}Z>j~gewmh$wmdHwsT(uBDE!0kH<=3C1e$oK9nMe$E==)Q%O zh*0l3#&zssXQ=xeG=u$`ArrP=G(PqUoVIAy-EL zu~ONkiPEzfz6J>3^0Ed3Xv#(aA=#&QULT~xF$=)`!01!uUg-qsLq4z?F!(8%aKTz+ z4y)mz??6PD5(2BbFj zNR;GrJ?lj(<=4vvB~M8SOnHfk*{l^47I|(^RWc{t4q- zN}fflZj<@48klMSJVpQO`SPO<{FN`iWGI*~U;oPO-!t@g!at(^%YT{h&zkUOhW=89 z{x(B@N$uYy{+$f{ht=daBhTFWS5Ywe=OTZre7}3=jPUoG@QYi2E1CaN;y)t%v)2A| zk-v7x$nWksxAGq=`zz(>zhmXEgg>l=MSdSO{&7G5i%R?_;V-@Qw;}n9?|$p%zvsJe z0TQnL{!6hVZuzRmXR)X!l%?;IOrJ4n67I{Ju)ZRigGK4X#TGg#s=h^Gq05)mO5)Z(ysf4huaORt^SSndlN=2 zNZEEq$%2$V=70cd*cJh;W8&(QU1G;y)c!`)?fDal^gj+IeiIMA?eRkq+H<$v-zj|j zt0%uZ>!F z>Y=lq29eG>_J=y(Jp_9CJQ^0kXaL2dEuNDVgOlkb(2N^vI@43m8Ud>$O%oIxzr=7azw+6*!nGOVVSN_nXOYT`YCe&Edg2*kfa z|J_-SopV}JIL|xKW#=h!o}7Q+Ih;vcK1-$ZbOa@wrR)Yq^_hh8ls%L1M{@m;0QTF{ zzsb07ne?si>VSm?6I-N1RYOae3uWguRHp%)(O-I4j{uBGO}?_`UzA1+o|t6am&u+U zxQDS))Ic@opx9Q)t|q1U0F{m6z@-=8lQ)p5rI*;75kj^S*9N!>9H`KHL}^*LiC9{) zbt{=YL&AMQo`I?%gTm8wF|}wFmy!UoFyn6>AcLE~kW3ar(3x)#P~-9)h#<}2atd1++3F-&?LG3MiuB_z>0Vzwk?DCeH+)$ z=@k2Mu<(Zmzgqzlf6+iH23g+=X1B; zSq%1a64u9fQW(^1d%T-kJYIuCgknr>;D0cn-%RP(ddt_C>`dzKH8b4`oCpDDOuQD!kro>;XeSB5|k0 zM0fl0SCa?s+yp&&T~0!<m+>SkFBb@APC^viUqji&1#JD)k+?lyGag_0&ZB)v&;E zq29B*cM2pF$L`Y_@RMm@SR)Rd9(ozY`!PIVJ>9YjtS+iYx*$p2V89vAn(;;3hPHl9jD`!G$e57Y9eDUiKX9kOW@=HdZm4}3 z&FJj?-9qTO-RhQ_Nh`1+S`A2L%bb!nfuQf`dncM^~hWRk%+ocpo`; zOWw3 z-hJT1xmHh;bXec+t>Ye^t;?R-)q|YJOiZe2(mR)OJn66}36>7n?i=aN7@flL+9Nu! zK$@I?HKa_VALTlcy_>O;ZiOmJY#wt^cKt=L^J^BAP?6V;{K>m%wyG0iS2mRQbkudn z**3bl3;jLB`(A)E5M*#?Lc#l8_1r6iYeOGf`YJ<<=T!_Hrg!F3$77TY4<^%PrsnLI zz7+Jt>Nf2y*#>v9YX?^Z6<6uNCm^y2lV7BnPq&X<^>?eARZt>^E>c%Tw>3Jehz4=@OcLLT{ z*VK|8Xnbi~`oZw6VLXG$77>~DsSnp4k>8^YG{@1ij)<~v9H6T{jGU=oCu|>aHZd?R zoG^M*eQ+&Dagm;Rw3K@It!8=qtmU4!NcHs2j#S};7kY-#VwoXt^Vx>x3!@^%bK}bU z$3I(VSEdEeQA&wzbKm!6&px@b)&8oeG=#I#poS}L2W}AV-4Jf-LfUOjm+e&d(MoS2 zrh1Wn4_DMrB4jSBM!Xv zBjTC_!L0)OlDZ9;hIxa>tmu`TE06PZo@OMzd`w&$_iE3P6?~>VF>OGjxH8IpH*eyj za+<-EJY_`F2d>PJ6MkLxFCvBP{D*h(MY^BmTo@NxtLJ*7z>oJ&o*w`6XUqRb?~<9{ z%&iWTeH<%8=5r6dV=&AYwtWD;U2O#0*Ll_*T6>z9yLZe1J9wREC*Gd!Y);D)8Pdt% zEPhXEx1d%IX1UU|` zq}W1{Y;F7AjOtqP0sk7Vd@>j6=)Q3Z`2Ki5Y#OQ7a#+y7owtiNrZvvoO^K_AiG(gH z*cO>aP8PT0$e>7%`9_#ttRLXjQml?zB$n|faqvPR#YMM~JLbv+^+2oC`Frp}C5 zKQrQS{ZJ`$|Av((XQlQt{Ak*?8mi8BM>C%EOJ6NCoW)9ivE#Gkpv`ENb7!$j7OIrt zlCp-XLvySrOY_qM(JxsuJ~ZEyd;#u+A=MV6=fMY(#IF!8b(dSprxpjkBAVX_m;}o; zxN5Sr1%-pJ^Ru0jA_ed3oSAk`Rod^&0z12T=H7pJ^AE~1r+|d~DOU&aNbGIyQN~s1 zNQZryOuaHPB=1<=Z!pDCu3wHq*iQU#s=C|b1rBkerY>rDKv|tt(rdoS%d!hpfwd-R zPm1z}1X2o_234MvaIWt*3RF91U+CF6-BP7J&MD*LQE?V>XBRiP;lx;BPbiRbtv@30 z*$n(r(PwFwNq9Z(DN6oTb#uP3mpHEN(mO2nO?$KM;J#pTG#R+Fmsx@UMuX0tJfKD+ zhR)_8@^xD%57Ye$?3@Z(uwLlf4qnT>>*`J9!V#12QDu_shz{V^A4J=AZ&in&1v`~E z8ZlYaS0oIljcA|@$;svU56LX>sf z`de}3ELV|u5B43L;af-{$B?OA6CQ)ZIFrf>1I)We=2gl$0cJ+e!{V@1A~Ohjr6Xcn z4wZAv;-u2H(t>hrskydwCj};9FF17Ak?rzh;`oVn9!n7^>ru|5Es?LA2Vee-g_stJI@8r*?UUX^+O~Hai9Arhrs&9(Kq^$!xdrzn9k)NdvAG< zH`JU&vlQ%Nm0qHapnA5jNjan2$77%Ts<grj15h`-qwXc zMXwGb+S)J7p&S)Y+8cb6qOxsKdI{LP)%Lw<)MKp!S?R+#J0q??WUu$U5fiZ6mR4F| zyY=ynrD%v9Z^ezOVQ(rL@s6a~B&V(^S(N&xy9$BJ!(WBsXFh$=^Og3?)0Zl}>x8l$ zP!!8bO@`BvI`7pbLtY*%UPiXh)My;tmc|k`@U9tKe~#TxvU)O$*o5;9XT7u0nv2TO zct962-W?gk&W0WT@jLt8nqCd#LR|#jcj`7oEDWF0!SQ2xBko+SsY%sAm%rGmX5jO@%qVVGN%b*ZJ_L|nft#M|jt#Wt^Cjxk;tL5LEzT<%aFs0Y{roSq< zs}XWWuP(S{fNOKS)4?wS)UwnSNP@HoK!fJE@Z|YpPfZ59G#!t7QU@9NHuVYIw;cr8 zt;!oitpmCf6hB?zu{;Su+sbd80Ds@ofdHt9^gMao`;ZS|#-syA25U7<50%rjnQ6Po zA9UiSrrnaS5H(z%7b)JXYC72lpZ)}qU?%l@akt=4N|x^XD957e@{xGlTFoD~GV@<$ zp*+dJu4%h{3O?Rhj)qIHlo^H%Dh#X@QCtoDpjHtS{_II&FPBSOPXd?Tjw)et;(94K zPlavIDg-WytK-;=Tv{;D&!VV)vTzHy-3Kp2h0;>G5xf3{walLDE4<|&?Ps08l7RHl zo*XNN*kdNC;VI=p8TxDFz2#ze69?GQJOYTu;2`B5#{Em{SOc&$Xg3BU09j&`hBha) z*6>Q@c1YJJ6mc8++#&?9<%lVdtniW+W>lgCv8ebw7y%hCEg0up3=KckRl;<}IU z;!O?-qNhXderh>kDS^3*8zre27lVV>DkiI8;4>l3*QJz5jB+v@$XCe~@1$i|j}*gfWj{^F3kTo7 z!X<`o_MBCeRlG@RkxHp0S*nmy!`OhGLA;8kJD?$Q3P-d$K>RhloRpLsJz~Rg8)S znO}jv0-rceIW20HaD&C=lHuY|Ku3Nthovi1_6P0*w9`EVFj9D_HJ*9}RwKPx3a^Bi zU5R#UnxZ)vMF9HuUN9=vnQY)5e?|bsGJ3Ip(PVI_Xlx`N--mxi0H3duFytSoo`Sn+ zez3iKOaiUDIdJgZ^v0&ILnxtalHf4q44XDNwL|(JIsfCg|A~XMocj;QL0L}g4O#JJ z3r(ak^4D+3JLXk>rmeh8WZ!x!e_mQs>7fqOQ4{!hGa9y6;1cg@eQa>$-KMAu|2te* z^NZ@Yr+p`P!8})DF&u>t_V3pBUX6BwS6Vow9H$>1fYl)CdTr%tY0f;g&pbFz(%r9`8fROni94&{=i=)Ux<-sBQ|87>L>EBi5*16Oelmq%|lGc&LQ zWBXOQ>#?=kxpeTiOQxH@s9Sqlo(t|myPv|E%MN~#Jp~^JmkQwTX=nBB{vyEEys<^n@MPcX|pOK*56N67&{yw=n!} z>1Q}`aHG=(Y<~LGPE>AbdjH*%(Y`Ze!e5Yke1i5WX9LBpb}^*(X(<7sDD|P?>jQ+l zTxiGR@W%{H9U52To^D5U5S>&>mK)ZklL zj{?Iue!TejU*9p43j^4-E_Y4lR&s{IeE z|MAuT1jGLWi8Flsz=Y!wj{py|7I1bhbH4xtenv!l?DACwgL;fdsEpW5?_jG z9%!ftxB6Wo(`txS$bbGkBEj5T3V;?!26^9HRFOv)RTw|6Ti=gacU~8ia1c>3x;r5V zd%1p?_Ic*iW4u8+b86y{;3KAn6Ge)b(-)7xS;NGh%Fh%ThCI4huOse!Ha3_IPmlD` zZj8z6%eL#u)mK7xA`)ZFOu8Hb(ehq5SUzyMyVStpZ}@ce8sUB2yWMJVSe#TkB-y1o zRaDOQS=9s0lP2jW?+#ac6x3*1CK}_jS~B}!LZ#S4B)eUA@ax zoXEZ$TJzr54d_S+B~M)HC1|zPwugQ%%Zl16yeV!0I%>9f3dVy})NY#$WhRAZIc(Z!Lm_B`9H;+8v1W$Jup^bCZ8$O8@?F!>|>#7{pV> zDI;U2!|X2cF6G~5ZYw46N^IHo@>$7`NzV^j|mYVm$P2KBR{YNL!I<<%VGoJ+BimjAVzb$d-jb=PnvyByK zaermT_-^>I)17uw)<6{JzU{|v(Z;z>B&vB>Cvw#k?}&sJ`8Ri4qVI|`8T3j7dXZBU zrmT)fPB(n4{wV#n>a@`ar!uVPqVejh;)?3UX@}C?Rj=MIELSmucU)$ga#!#lDQ9N~ zIX#hg2X@4Fbt+XmE2*w+UJo2#zffYymGB<+Jb(wO{V5JW<;>^e%pdmkx#yzV=FX|W zafKA$%PS5FD~or1OG~E<S_pKfXp-Uilh`%UL(G|!Lqj!sL zA?g)dT2rQ1z1A>C$(K{j=7~x5I#Qkv&ZjRsl|$#)Hp*G(mzjg8f@pbtt+&muY+W7E z@kvW}=lrmSq=98@z$X#8*g_#RQyZ%u=gg>e(kr*CePXheD@{Q`@xlB?0;k;YI%eg| zqU(>VA7AMX>)sHiR$RV?D*zdPGfzc5-y%fK5z;v#7CqjOg$Gu$EAEkedB~=`RiCeQqx(&SP&FDXpOjtf4#CTrsQtx9;eexcensR$7Wsa32+d#Y?cU|10 zu3T6ntGJalvJFFg=H8pCs*yMEL_~^b(~*P%Crl;~{|V+sZ7g|9ZIYIf&Ju2K7k8n}mu42el{>UzsQ}^@EGO?=$Qjm?oHCMyrdv?t4WoL`$r{LzAkR7l4%h_M;a+ z8|dEFDZ|A($`T3L<;Fc2A3YE0l*xZ)9Xs_N z&2mmXbia`zZ2(;$d@@^t$rgjHmFVd12w6lMO6%Lfo{(~!XC6iAguZlx;2ssBEu3M} z`VLpBV;BBV@!~6+Jn2h)s7#@zcgQWw?h%khK}3PtQs0{|-dEnwsET)${JOGjhl=9W zI%(;gW|9~y&!ytQa4ATdx5$3;e!4^8$5n%Eu0qrpoMh{`w`}XUa*8`2HJI-zJuQdS zBm;ZJXa<$rI8Uext%=^Z(JKd7M|3cmyF7>&or!tm8YoJ6(JA z+x;@6?>-h;T3uadlb!6KQUE+Yz3Df!Km~Sqy!VJUi~s!jlBrjmkqP#v1F@+pPtx}j z^r~zI$b1|&IZw9M?%hL^ak&fCsVwH>bW&{U&vhm8+~1ij&qs;3l6w%b{Rl_V270Nd z{i0;^SVz9}zV=d9eMUvS*NEqh0|PsL+>~ljNwIA`{k)b=cg(;Q7=zAWnatVu`Z z3P)mB{!npxOw1uV%$=#Wrn0R1g=L^XC<#kuf{;u%U+a^k;MbpcvN<2&-Wc>%$g~%_ zVJ9Z}MR$LHA=r!J?S$OM8_c-WXL!7wv=Iy1oTM!WBqXFH`o+g~ObeIzi&X7H=4HvW zcgkD?VkgVvcGe96NY5t|LfTRHE&;s?gE0(&>4ry&5;e0jlN*;lEKMFgm?gQ4HAQJI zvUnoCW$7ziD4V|$H#T8?J$Yx=y6ni()LE^34Emz&*?fn)X)| zh9vw3E1r=K{_nyC=(zA145Df2A4{rpO$sB+CeRD&Djl+#W=+{HnQI!8(DC`LIz-U&;n8pCyL9(;Mjfa*$%=1t>fw;DYQ zo2QxYMvXH@xo3`5XparLGGsGnPZ};yM$}7(XHdZE?!HHJ_$|Bt#gE(2;t#{;4uVbu zi>rdY;<^|JRH$0AxW*!MrtPG?17LA9ZthaqL}_$~Dzlq-pM!7KCd^{@4yw8pNQBV5 ztvF^Pw1x0w(DaSmV?XSf#|fRqmfF-fW~fV^RB}A#Tnz7JTJ(Hg;rOP%YPOd0e$4wh zZsHS0b%JSwE6EjA2|C*oO8agK45yLITIO^Mu~y`05lDAx0s*m6oQ*JmB?IZ_30Hc1xfN3#GEqFd7&k@VBJt*AEHi=(FbjHi%agbVcm=Hl=s0C zeyVaqe$tS-=aD%$Yj_{Z*b-iBxpZ&JR=qFcdN{^aQtI1N!51UgR^Kf2Oi_UD=6&B5 zS{zZ)3|yJ5^a!_TvYdtFt0^Phv+Gk4@#5-O6aZDrQzT_7`{b%Eldzz)%p4>8?VN;c z@h-ZmDw{m~Ue#;(6N+Q+lod=In(fG<$TNw3y?oEm(^Wyqv4Rm9aTzrNRE$%>|>S z4Wb8YZyI(O`cinltui^u{+k@39enj#tr zXh`hjw(JQeCRswl-4)soIhO+Tnm&r|{(tR#by!@>vhN^4g1h?w3GTry!GjYB7G&_j zU4sR84{jk4+y@H;cM0w;!8Lfuo1J&hKH2Bq-0btd{jTP}nd<&(^{VRb)m`!{NwMX7 zYnyyoXkhQqYrL)^n>QutV=@k4veDOx0)ZVqYnMiA60qKKX zIW`BDj{RV~(C2NUW7^aVL%QChaMq%t*!oUgZdoW5o?4@(qg-D!EjM53%~jv&_TC6| z_Xkh-N4i|u_#wjByYdxKtO(WSnuE+smN>%%cqtdGeUVc*c`jf@*T76205`%RGq}d1 zmf*OKN$kav`dYSukpvE4c5Pv~lWVWKx;i|?P}Y%m5Jfw&8X0B;uBj1wcFP1YD~I{wazW^Q<9a)Ns_W9;}|URnV#3x^-2b%6VYxB&)%soY{-df zP^}EyngJs+eY6F`wnRQTv5@j>CtAC z!0fyjTbf>k5Vb+2R8pV0wi#u3#2c8*R6leyVa0$zc|GNEg(60#3pk}34(miSC%g~? z&6(Hx48e^m-1oCJgWLgnn4T}jxG=CfS0+boSP9EgxklbsL?Wfa^3kHP8EH6Fu@E4} z1#G@;Iid(Q88>RKm^ARw6^wdt^XR&YM_up1L%>1!{+G?QI>wCGl;qi{ZDurS51}b+ zRzPeH&Zzik#gUk8CG%P+K9o~!X3M}0mkj=XVQMX^sl|#0?+^fP)Q3;oJNPATLz5g5 zOL{5Ln_0CtPN27o-~IEO>Z8y(*RHjWm(R)rC1`nykY5!8Oy~vNwz3XI$vS`2Dw+vW z-jFn$AgtmtBJk$EQIAoebQiL*K`*5}doSso&b1O^*tR#RBbn;+QLfi}rv5i-;;3;P zo$G>KqS(?)=tvJ>mhE>VFWX070%pzKGs23b3JEi%rKfrV$gGUaW=NO7GakWOhec)EVHjuznLP$j(dR$m2LYt?|O_(BoSxg{Y2oNW|_~anSBLV?&_W4Ks{(5 z`lIgnG$+XWgd)6}ZsLZWTpU{u4(RHP2@%YV;(hmwOlXb@7-Ho>eDeLyxT?VKcmKbA z2dC2Zf1?+`)}lSXLCe2A(d+a1BU$rzvi|qI{{%Ve zZ@in)e$e|*Jn{!jen9^2b$;;3e~$bo2Kci_mZE8WC&7Pi+&}331M<&CQu_xr{D8?1 z$UorygWlhf|1QDrrcd)9CfmQ+dwJqJ^7l&nj{JAte`X?o-}^fz-}C=+&}OACwPA+sz1^DyGQ;7BMJB*tbEJh(WvdZY#PZ{ z%--|%)qn*<58v<~Bfb7%ABP5@k9;#Dt3LjCDEPSK`6qriWru>N<=HQ>>`^#*1Q?3g z$&P({OZ1SnI4u-QdJEFY$J#$ZE(i+XWRRp#2tzQ?m`a_gA$@KOF(>5+Z(d-J35uE8 zJ@R2?bqY&;6kr4e)RHE4Jpi8MX3T*}>F$bH2&v|!p}4-cG;2%nu5lf;*BbuCOYQCf z9s9P&9}?rxG;^dtR&-OaJkj{m9Mq_8e4SJoaHW?n&yN|*tQwUgZ;wjTb9*Lb-YPOV_^?t8a7r+63gA1zN_aQ$ zBv8WDi3@VXg9OLm#ss;K8dZ;lgYe(mcv6NMH|qO!t$qrqw2C#(=AG|8pkK6}DOw~x zzDv#8#wX^h4fUpxA6MQ?Sy(r2YKd-%Z`71|W%s^u&HvNukN$2)cX#d2G8OAvY62HW zXD3fQib~F9NFQ0%z(gty0TKNoq6$i*o?ix7S*8?lIUjT;~fn?8K~-hc(&9cT4K;@V6v;{siIFxkeN65CLN;DLc-hCsxA5uHV**U&|5hRKe|j^iEwGZZcfj&AYj+gX{e@R-U@OL zu~%veg)NelHi)V7%#VCX*R|(BY}0C`sun(IRXWq)rYs*{Q)d%vc018y_=+s;ivlnA z^riReQeaP_yvfeVbV;F>WD+v-T1x^!VpT;TPY6+nK!Re6=e+_m&;57PGI={1DLO;s zat}9rlO^#|=pRTUreX8G``jPQ%3UIUFbT55>+Fav4lfSqh-jqM+e8F@-Yke?`R#Iu zQ35>)e18JS{Z}Uhvt&ze4VpZ-Jk4PA>f91IDRq7o=K|x`RhL1skSQxqKH$>!MU0G~ zT>$-s9VSt-Pus~7i!}2Pr++xcr8t(LDn>~5_(6Pel{{@DN0SOy1(T?KqhEot560&{ zxQ6c!Pk)FZ&N|CNN7(9~Ja33k(Kdgy4|HMII#3JFjy0Zth4Vl_HhhcJWh-=RX+=F_7s>(WJlu$ifh> zJx+{qc-NYT!EKyY$VfPxu*D_p9k+=Q-;!{uPYP;wEe0zh@0RZ}77iC^Kdn7NvZ4W- z&Y1`Mv4cmWEha<<Q zqLkR56L@176I}4uBo^6@&Wm}Fv~n_vpS&RKHFV~@r%XQa!j=sIkcHI5d2G|3!O&1& zS?;&#g6HNNu8a)+a(mse5z(Qs=cG?9EK=~2bbs#*iKY?aO+I*82&J*p`XRjfSm< z(d$vb=&j#N6#;stubln-?kpy0ehB3ejepkzxP?#O863VHIqy%oBqm~}hRuvFQcbMu zhl*f}ma2Bml4qCBna7y7(a^rlwsL&hM}}u$*s%{ZI_pBBJmFVDl=xEhhRD$8MeC-H z)Mi(+#ewT_`VMDo-4;#gN#Lcj6XSZQ!0L&o9sA(wskQH^bW-AvkC;Zlo`{##V|+bvk&*>(<-#*=GxzOC{rqV zuWE~=rAkxYvz3kUk3`xI1$<%>1g(_Fj_mNbzv6fv+|gn_4^JXj?Y)amAQ11znK@Kf z_mXJXWHN~da!hn~O#GqD>a}#J%z|eJItp1;Otd7?V+>iq8DklySuL0<4$5=di z2~`Avo4(Hhjg8>_(|)}G9_LB0B}+n@9BSU|0=j3Bi_cr+uJ)!C_j^}RImq4#jv7{k zUVC`db?mkA4mKuhDhqbo`qNvKF?o>lM>D3@TsjnJA~cn^)KoS*8+YJ)FssuC7+95G zC8IktS}%+P#BgD@gVe?nTe~8`qQD+B-)bP-KFx( z?Pmq;d#RrqX%k_sp^<;|n?q1=6&yh{{{qQ*1JV>q!~FFFN$aNS6>U z5y>>1=V{ z^O{e*h(ecrqY}*EM$e)!%^TMA=+gGK6zh1#tRvPsvY!Q$e3)lz-y|jPs))!a$jN-cn<#InR|t@!$=+I4(AcvuD#*xG647w!!K!`VPK|1?Ey)benW^&rYBqC;bre zmA%@UklhP!^P@M`74nh?$XR2hf|oH?;zxT`h%c|7ce-&cA!V%0(2lovGO$2KKk}T)%t=^0wS1Rp&u7jLy0Dlrz_wa2aI69(ndhgV{frVu)DFKABA+T}M>b zWYOuHh=KsiNkmt+(xew<{Nv4}dOPkB2k#sT#HVm{AKSqdV~_xy2ecSnjN|dcu?M7Q zJBJQF05D{A^<+I>Rmt^exoNmd0#){2FVwNvOY#lpb8mzlC61yofY}{3WoV?RjKoOd z$QnN=>xSW>HAO2p`$`^`(`m;Lq?A zP6E}nRZWe)C9%-&s_P8#M}0$3q8p=kGFcb?kW-kux4Zkly3fPq!9zVry!E#pD>vYxBJ)MH8@8k^w&q?f1hp7y-m4i+zhx(S zI9}e)#v{6S1xq_F4Uze{!;WG#-c+v=!$?Dzl*s79@f1z+MW%}9 zGqF^hS9aCK2$%x5g^Hf%@KXW>uIO@Mx#w0AlamJmuBDTcwB`iJWIt=4G(7PGc@5e{(7l5Q&>OF;?(>Jtz*E?hC1WQ~kf8P46y${& zthNoVS(3|jM(VxMAVk%FI7YlDRCl$Qr0bniN*5eU5g3^UCiB3@i$5G zG@qJd#&gp66a#Iz(zk%5acLt6v9}Tm8^^vZk9JNv7&+{OFm9KBYU?Zpm!a$(QaT{T8Ig_XYG~bI{{!p zhcyu|jlC~X-xejAP*k|1&|@{?XT_xlS6ICp<$+Ra*c`xD`jxo|G-E>TAeQ!42!6`A z#^{Tp8Er-GbtNWkO=}h!_GUdh1oryS(he0u{`3nb+%zzh>~2pR+0IyM0q)rXhz!CDI7d_#YS$PFR+gV23zi*0F$zk~j&r#Jz`67sg5OY3aKO zZ9d3+T}XVJmCUy|K#dgR`Ki~OnAWZB(Bo%1rh)`4>Cog7;r!-L z%Xoav;9jfdmLPG>m(*rhayIv`VpBshFqL58sAzz(Z0H<95yloTVd|S>fPt&Lg0YKQ z0av2nI95TsS5%S$$D{Q{lLI(WKvj*Y(QBvucQZlR33bhGTze&D+Pd!>w?X4BMkYyC zUPLEBxPlIENy;j{GQ4gcgOD2&XChKBwuCA&E&4?;;%*#nRQDq`t}>h#as}=_Zmn(4 z34vRmu`f;~B`qB0d)*xbjd?IZrcWJ&t!K~Y4o5dTGI&2yHKa_Mnx!B=d1`cp;PMJ+ z-6cvN%Sf$=Z1K*^&f8*gWApV8{4h;={{u&oU|vE}AKqmQEm}Rod}glZ6vu{BIzmgh zdyo7O%G(Qf82k<#SoN_nVhz?ZP>2=>Zy7$wKC5maWRU;XpMhUDf zYcnkvTM`$y9*mz8#f+XZ;*&oC5(U+V)qeBNAdz=eE28v0PYyK%uykrgk#zf;T!>d zsa47{;XM6%ROiX^+DrXNp6vuBbm5%0Z~qpZ`w!Tpe?C}O)G14e%gL|^g;$8=?#AZ0 zz&NoGGQE6ebF<&l6^(E4`)?nn37d-6PfHhb-Vp%J!X*$i3FWZ%D}WeK^{lxYG1q&^ z>W&M>q{u50LlTS*O*}6aaa=x@C`d{e@ zH+p~K<<9@ty!D?F$A6-(MWCr{|J*$L3IP8$$Nz!}_|MORe}1(8cMbl}S$B6+|H&)< z`G>-h$vo2wKiG3bDvu1v>l|?yh>QqUjev)EjyB@28lO^Q-V6eAKLD;i#rG5{_L7o*Z z*}g7OB!)h*7wJen*=(lCN)Lml$C`x7b}?(ZV&2Z{J*m8+&59c6NPWEjVe25;A>1Cp zUbM{oh_vlS@kmW3H*a=YckwE=)7>(hAqndsL!Z!XU@I1bR3B9ZBxvQyx~eg$(H@pJ z{H5@d5q=9*lDz!2=y!x&GaeWZk00(T>TJ1J>GsZ^%OG| zH1(#mBq+|s%jujua`(beNLWhR1;usKRS7T2KR_UfR=OvPOYo%)oa^N5EVw@c_T&Nc zba81Hw%nIUE2C;ig&zV~=}u!d zs}`%;?35ziR#c@BW;@owZw0g_vz#&MW@VkrE)Q32Pvf=jD4?mp*+YX+>#4d0jUH4i zCP|oKTvXW0&EnwmL{~KV%>Cpw*KZ+SfBs}3L1so~M$Df*8aaVl1#r!M%s+e%fM$q2 zMXR#zn%lHI^=#oJ5gg1E9ypjAVt;PF^2I`tkO%Ved~Exu){2_s<1#aTw|(wma``%Q%cupzn8d{Xf{1p$6y2qNHHgQ*na8QSQccwZ0NAbr)>$GL$_dmI5)WnJx}q z!DFoq;<3`|_v8ZFqi>g+MtjR+v)?AZq?Z3U+872dMeOw=$ADtMSd=3fv2PATjH3~Z4NqSA(1yDtEQTrd+lw^BzDZxW*w zJwj}VX_2s!qX!AnQrr9?4~JJ7lWQ-%-BmmmWX*|Jr+O2+9?)SGyRgqnz&#~=cXcNz zR);sOpmsp*!yn@5mE(5YZdj!kk`rj;;d+tFw2~soPQ#}L>Na>`Zg=EkBRg(A2~Vr34E#jPYeWroFHAS))gzHX`f-gNE*0=rL0ZDo7_^4xcx z3P*`aR&QS{=rqjjjB&Av#DB0>txiPqE6QA@!P|ngpbDzezV$`b;5iizaj?AG|=ia`S#fWm^|G=xz{Q)6_A(l*tM zSJ6`QzWzq0p}D?Z2bQg}XMhiQA_jj=G2|oA@JFR{a_hcmm#8Ihe-(h04iYUKI;2Ts zpr&LRP!xsXPF;OZzNS5T*KJAZq6vyKZmW<&a){`8+_f+&2D$N}g>reg3Cp?YzsTP+K&&4gM!$+TQB%(x!SW_)5b^PN6(N#Do~>2xLUm zb#x4UyMEnI!Za;$s*PhE>L_L6<@4Rng1wXvN(f$OsB#Fei`YiP5Df#B5ak|)HwoRl z*)Fs1GF$4SHH=w1bw0#$3(XU3YkD=bwjIkzAaykPKC9B4-)S69O3t5`C45SN@W3qc z<>SP!fW&n1V~7YhK+nJXj-b9a@qjVJvo7yOWYCJgN_quE%L{ucg1A|ccu}1tP0Oq~WM0yk{Qu|a0!!|I;s%Zf9 zT-zv6so<#xN#IhrOR4kJ%9yT2+|D9pJ;(c#r!3U9iDuMv>WWG0PE3BhZRty{>&tLH zFteGsuAZ8uSyLawOp=$eabBI$EYz72u7MrKB5S%H`El!i1C9( z>bo&C5}|rxj=bCFQ%9Nt*mtzSHYYw#aGcT20EBM?Rm4|-@VWajY6<%2lW>TLBU2<< z+b?L2@>9CT_RD2s-Z(p}+->5JuZ})!uvL8&P}EB@ ztRZ?ZSt8B(!F+OXJ!~7%5o%n-HYAEkB+}ybjma5^z4yT1ons@I6lW}D4S1;wT$)ws zeYpxQ7=OIc)Jxo;D{tRyX|ZCgw^*2#*VyYXlyCXn+$3tmwskq7_Rw zM^hj<i(BR6R6Ql^4wiL$1^tHmt@#fl)b}sJgN3Ok_CA+k>Pny{#y$?-n>9Nn zeF=JWD5ilrv=$kf6=@Ik(Xb>HJ_qxdd%x|Y3+QLDRST44=OJ8lr*82|5t5sPh$VtTz@a>#$(m<#jT z$XM(^%HVSu$@m>Hm_M<`t&n@85;$l(2X6_#3ykh1b?^-@z`}j`yxcOP#nH!ou(aas zVhCDITV1GBNPYJ(#Uh-L-41UVUCpHuQGTWpzKKj}PTiA8{F(bD7qg38^A16JF~I=# zUK;Z`QSv%&0XSfcTOX=)WXDmX(aDF$ZHS&W5?_Cta8& zvpM&G1@~ESVZs4T=&u2vue*=#(s`n?&1dC1nmudPkHtqFPOHsuA;1i~`4NO~!E%4M zXFV$ee*>h9wlV(bQ8$_u>@)zs2$ zhy4;^wLU`vIAL;8K7@Wz`6J!h)`Zw#_U-y{`uDIoh@c_5{jQ+)hb#50lXLxY z;Cd>@P~da{$d}rh-#FAXsyhX+YxcWW@gdZsw(;h;EYPs7u{QCHMw2Om>cNVLy?77a zam@@0pzlqzG`vYY$>BX$f3@au>#_sp*Nr&(J3!bO6|>DJ>|SH<<2ZQ*QnNk)ln_LLdEA?)|;ag$+v6wvIkFBv<=bly}An=-$j7)VN*{0ew4 z5v%g?N}5b^Gn88~83|Tuqr6@P<`c1ZNVUAmofl8n)<7L(sm{t6UUH5!m+k%v#fIUV zeQR_ydwxAXZUJyX$8|{HY%5DnwTE4;J;Z@&z=(y&zES)L-OZX809QILD3`PCa%2vf zq812CZ`1&@k%O+xbbT0nGdEN^5Udg8?fEnPxEaH`Pq;DoXRig!tQVK9GmVP}AF#*Y zuh;K%gR?>Fg*tSt6ILTIv>H-|c6ddlqil3E!yx)RMJ4Xcm3HX$@~Hu?5wd35shd zlM_4C`6PyhNHk?xi$rG-(}oqTu8QMCk^tb>0oNSY^^zp;WU~w0N}3o(Bdtj)brVf2 zT8UMW40A6*hDI=S6`H*V0F%=+q`i3Y7!`KWjLPg)cAxCC*hliMqLMFkkz908p@*G= zpioD>z2utO#3!{7Zx;EZzRKcMzgO&dr;o5dz(D9}$iQKGa29BJ3tIEc@lkd(Ph)tK zSAs5Lq^Tt5N%}!V&O&MHEFY_VoXXZjFgj_QI2D1c4u1I3wBcE%C*wUth>1jZ&scrB z--3tpE_Amgo!|_o8SMEl*;HbU*wjXah;Y`MlvV-{;ARVcUnSo=ijdwW zQ$}ni_`T7u!Wn_-rOR!Q0YVa}naJXO)b{zh34xdx@9ECC@^IJVrq{Tlf-@+lHhj52 z%(DtK)K5gQJU_<7J||C0g9}|gqX;6dO|Ub%Q2vrleM4H38gEbMD{VLoM596L&S`i@ z(Z)B7$55lK(_e93AE}uj$>C~|bO`}Fp6%xzUXtxW3s}(e^yl{F=a$9Z8&&<2I~G9%Luw4qh)o8x#=u&QBiG-r*10j=b4jq3F7S&^=pxnMs1 zx&21*RRfreOFJLDuw>$e%14ytSSET&_4jS!K^8oy8fRO2r!?=mHKHGeo#<5Z;G-}{ z*MsHqM9Ik2HR}!|28C6rJAp_q7{t0#`?=PJc#RbK4v2E0`8JaWjW{k9jiHZr1}{BD zAYKQK00aZYAy0^dYFJV z`j8_f9L*NA;Ysm8BkQE()5WuZ1FGX{o<#LYVwWIG%hf8~7(;M~Us)RchLI&Z`Xfei zwX*}ppqvk2F#p76y(3GRvtQ$RAu7x!&xK&D9H)K9XWs46N;7EfIht5PI>HoS+?Nfs z+Z|azh`t}kTizI1Q)^tb`rUBHVNbPc7~)QB>ltDwg4%l@gqO`Vv;fh>+88$1tO!C! zhESwi(RZISKsPAZThw@~s4}ZmIy*H2d)js`~&#HZT?Bi3+o5NoLLYa5hx$%6FZ|iOT zrBUjE1DU-2q9qi)YF6=PCsJvXKV_q728uUTop~`qnmype-S1Wf1@tf%IV|LR{CWqR zcxnm-{uuRMQnL^Go$ni{$*^Dp9rUhLdoc6P0}7SlrQAo_t*Qe_6}df+`=9(&kuRVB zLxkx4-%UIJYv8?daeI&+SmT&UAy+7u2_+k+gYKn_{A8TXb99@E`oJ|KtDS z4S^SFAtNk~{cii#*64YBzVc1jPjQfj<0=$ISO7cjX9zwOAE(%JFAK-ik1Ab@=jOGw ztC(67_^K%P~+>OPd;Yta7BuNFsHBi_khx=D1lIl`A#?SSa&qQP)&`MN2PoQ|SSYH9z z#OARdeT8elXak8cok9cA`=^4zDWU;^q9)6*QoOt2IOA&WQn#MaB3PfVm#!K3*YZ>x z;zylj=4^oO&)%uz-M1>LXFS}TvZ1`2)4N7o@?M6zh=?IB@1~#6Yt8CDtr+y6PrC19 zst*m0nTF}z*5Ko<&f`j*vpJ>4R8dfVGpqIfMMfU|R89nH?DP`#gI*_{>HR((~x zqY@$2s6j4*S}>JPTj|VCwS^U9#g6zT>h8T$9bOCjV4uBS3lw9_yyXx|a-5vvnX(Hh zNjDOg?mO+_rP;wyhN66>b)6KyW3s`rTytOJJrkU)t-4@t*)9JH7}0vwv1+2MCNuPX zbcFI6#T731()H1|x&opff5$ERM>oNDrsQAC@`u}tJ@LgWWOMG|9$E zspxgqp;Fi^RD0M1`b)oc@@C)pwQ5#mNKliA)5;f)&m|MLowaom10#&3n9&g(ItZDjKNu^07SRK^gqhVjs+qiiTVT8AJ_eGxQf$-9uIDY1#$eoV`Q%@|k#3L&X zHk>1+AJSUBmOLy!ndI<|cpq4Vd*xK}QFc4V>C(8m&3Vbz?M*kdKpO@WyhGLSKyQqu zE^tD>K9o0wH5$n^yx`L_?;w$dE%N*lrMn5}O3!rt3OHQ(3RpEO*9lYk3W$#R3Mi%d z3J~XhAwySJ2Tu0OX24{KwS}RNwcAyT;b7;Ay1bfz?g*b-&eWU;W@^G1`|BOg{8mYN z;inTNLq47tmiOfbBAU@;lYTC}&pei{VD#BVOD|{7{dIg{TM{rarfPC_;o>tF>t6Hp zc_f8FZ93g{dh27f=9xj&(`HAre!!*>Z#;58sAG z4zDM#y!UE8f@0TGoHOmn&aU%@rZbkUPI5))U{=z;0&rg+`ucVYnP<*IGEWaFzTAr3 z%HyNNf&T`jwJI;KcnPA>oI5`>UiOpWJ$X3B^0T;Al$_<_3 z)s6@Qp!atw99>OIr4ckBCif%@HD&UyH}1|os?X>DS6|`mKe|XuU$)oETis~gGMd=V zOg^_2+3wo;<~B9kmWJXQhRM^9`j9Cne$GNXz(d~wq}mp^D8bJKJZ|uzn`a;!hv8XK zI>0SpRqLEYaXY`(N<|!|bwU#pCzHfo*>ANLW;La; z1!_apdwL^192!W1BVWqo(gd~ktoQ=-iL}nWI5rQoBZ!G8%VVmnE9>1nn>_P+@91ti z9Ch}|IP~7>^%hzX@TVPj;zF#AV+<5og!V69(9$(DA%3X?9|xf6i8{EUyb6QD4v zu01%6i{2HKCIqG*;<^`M!|Oh&nC4}MLcD1Exj2*edIX=lX=PVa*zR){6WFbNveI*H zSM>ShX;6vLRrjP%MadS1R_|$42@FVkh`c6li$V*w3-XPdaP=>Czhw7oqWq~l=|ghmaD^Ph#{bAkK84AyRt+v@?$_`j1k^PBkvk?fe@PUbMwdk@bG vS{(LJlY+2jpQfDx+0(RacS^=Mf5z-$m}``jp)7js6zGGf;;w}Fb>{y7vBT5T diff --git a/doc/assets/images/kafka_manager_cn_guide/my_order_list.jpg b/doc/assets/images/kafka_manager_cn_guide/my_order_list.jpg deleted file mode 100644 index 8583a3598e7ad0d665aee048c5964c9f44d9e42b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49500 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 jePm2Qk4Jg+M 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 diff --git a/doc/assets/images/kafka_manager_cn_guide/normal_modify_password.jpg b/doc/assets/images/kafka_manager_cn_guide/normal_modify_password.jpg deleted file mode 100644 index 0fd68e989e0b9ff99e611d7a7d15bf5018197fbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38847 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 diff --git a/doc/assets/images/kafka_manager_cn_guide/normal_topic_detail.jpg b/doc/assets/images/kafka_manager_cn_guide/normal_topic_detail.jpg deleted file mode 100644 index 99df01c38048d1ed3db7cb16321f1bd2a504a4d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67590 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 diff --git a/doc/create_mysql_table.sql b/doc/create_mysql_table.sql deleted file mode 100644 index 9a66ac67..00000000 --- a/doc/create_mysql_table.sql +++ /dev/null @@ -1,243 +0,0 @@ -CREATE DATABASE IF NOT EXISTS `kafka_manager`; - -USE `kafka_manager`; - -CREATE TABLE `account` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', - `username` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户名', - `password` varchar(128) NOT NULL DEFAULT '' COMMENT '密码', - `role` int(16) NOT NULL DEFAULT '0' COMMENT '角色类型, 0:普通用户', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '0标识使用中,-1标识已废弃', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_username` (`username`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='账号表'; -INSERT INTO account(username, password, role) VALUES ('admin', '21232f297a57a5a743894a0e4a801fc3', 2); - - -CREATE TABLE `alarm_rule` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID', - `alarm_name` varchar(128) NOT NULL DEFAULT '' COMMENT '告警名字', - `strategy_expressions` text COMMENT '表达式', - `strategy_filters` text COMMENT '过滤条件', - `strategy_actions` text COMMENT '响应', - `principals` varchar(512) NOT NULL DEFAULT '' COMMENT '负责人', - `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '-1:逻辑删除, 0:关闭, 1:正常', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_alarm_name` (`alarm_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='告警规则表'; - - -CREATE TABLE `broker` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerID', - `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'Broker主机名', - `port` int(32) NOT NULL DEFAULT '-1' COMMENT 'Broker端口', - `timestamp` bigint(128) NOT NULL DEFAULT '-1' COMMENT '启动时间', - `status` int(11) NOT NULL DEFAULT '0' COMMENT '状态0有效,-1无效', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_id_broker_id` (`cluster_id`,`broker_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Broker信息表'; - - -CREATE TABLE `broker_metrics` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerID', - `bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流入', - `bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流出', - `bytes_rejected` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒被拒绝字节数', - `messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消息数流入', - `fail_fetch_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消费失败数', - `fail_produce_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒失败生产数', - `fetch_consumer_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消费请求数', - `produce_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒生产数', - `request_handler_idl_percent` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '请求处理器繁忙百分比', - `network_processor_idl_percent` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '网络处理器繁忙百分比', - `request_queue_size` bigint(20) NOT NULL DEFAULT '0' COMMENT '请求列表大小', - `response_queue_size` bigint(20) NOT NULL DEFAULT '0' COMMENT '响应列表大小', - `log_flush_time` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '刷日志时间', - `total_time_produce_mean` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'produce请求处理总时间-平均值', - `total_time_produce_99th` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'produce请求处理总时间-99分位', - `total_time_fetch_consumer_mean` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'fetch请求总时间-平均值', - `total_time_fetch_consumer_99th` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'fetch请求总时间-99分位', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (`id`), - KEY `idx_cluster_id_broker_id_gmt_create` (`cluster_id`,`broker_id`,`gmt_create`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='BrokerMetric信息表'; - - -CREATE TABLE `cluster` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '集群ID', - `cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称', - `zookeeper` varchar(512) NOT NULL DEFAULT '' COMMENT 'ZK地址', - `bootstrap_servers` varchar(512) NOT NULL DEFAULT '' COMMENT 'Server地址', - `kafka_version` varchar(32) NOT NULL DEFAULT '' COMMENT 'Kafka版本', - `alarm_flag` int(4) NOT NULL DEFAULT '0' COMMENT '0:不开启告警, 1开启告警', - `security_protocol` varchar(512) NOT NULL DEFAULT '' COMMENT '安全协议', - `sasl_mechanism` varchar(512) NOT NULL DEFAULT '' COMMENT '安全机制', - `sasl_jaas_config` varchar(512) NOT NULL DEFAULT '' COMMENT 'Jaas配置', - `status` int(4) NOT NULL DEFAULT '0' COMMENT '删除标记, 0表示未删除, -1表示删除', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_name` (`cluster_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Cluster表'; - - -CREATE TABLE `cluster_metrics` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群ID', - `topic_num` int(11) NOT NULL DEFAULT '0' COMMENT 'Topic数', - `partition_num` int(11) NOT NULL DEFAULT '0' COMMENT '分区数', - `broker_num` int(11) NOT NULL DEFAULT '0' COMMENT 'Broker数', - `bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒流入(B)', - `bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒流出(B)', - `bytes_rejected` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒拒绝(B)', - `messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消息数(条)', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (`id`), - KEY `idx_cluster_id_gmt_create` (`cluster_id`,`gmt_create`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ClusterMetrics信息'; - - -CREATE TABLE `controller` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerId', - `host` varchar(256) NOT NULL DEFAULT '' COMMENT '主机名', - `timestamp` bigint(20) NOT NULL DEFAULT '-1' COMMENT 'Controller变更时间', - `version` int(11) NOT NULL DEFAULT '-1' COMMENT 'Controller格式版本', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_id_broker_id_timestamp` (`cluster_id`,`broker_id`,`timestamp`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Controller历史变更记录表'; - -CREATE TABLE `migration_task` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群ID', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `reassignment_json` text COMMENT '任务参数', - `real_throttle` bigint(20) NOT NULL DEFAULT '0' COMMENT '实际限流值(B/s)', - `operator` varchar(128) NOT NULL DEFAULT '' COMMENT '操作人', - `description` varchar(256) NOT NULL DEFAULT '' COMMENT '备注说明', - `status` int(11) NOT NULL DEFAULT '0' COMMENT '任务状态', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic迁移信息'; - -CREATE TABLE `operation_history` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `operator` varchar(128) NOT NULL DEFAULT '' COMMENT '操作人', - `operation` varchar(256) NOT NULL DEFAULT '' COMMENT '操作描述', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='操作记录表'; - - -CREATE TABLE `order_partition` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `broker_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'Broker列表, 逗号分割', - `partition_num` int(11) NOT NULL DEFAULT 0 COMMENT '新增分区数', - `applicant` varchar(128) NOT NULL DEFAULT '' COMMENT '申请人', - `peak_bytes_in` bigint(20) NOT NULL DEFAULT '0' COMMENT '峰值流量', - `description` text COMMENT '备注信息', - `order_status` int(16) NOT NULL DEFAULT '0' COMMENT '工单状态', - `approver` varchar(128) NOT NULL DEFAULT '' COMMENT '审批人', - `opinion` varchar(256) NOT NULL DEFAULT '' COMMENT '审批意见', - `status` int(11) NOT NULL DEFAULT '0' COMMENT '状态,0标识有效,-1无效', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='分区申请工单'; - -CREATE TABLE `order_topic` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `retention_time` bigint(20) NOT NULL DEFAULT '-1' COMMENT '保留时间(ms)', - `partition_num` int(16) NOT NULL DEFAULT '-1' COMMENT '分区数', - `replica_num` int(16) NOT NULL DEFAULT '-1' COMMENT '副本数', - `regions` varchar(128) NOT NULL DEFAULT '' COMMENT 'RegionId列表', - `brokers` varchar(128) NOT NULL DEFAULT '' COMMENT 'Broker列表', - `peak_bytes_in` bigint(20) NOT NULL DEFAULT '0' COMMENT '峰值流入流量(KB)', - `applicant` varchar(128) NOT NULL DEFAULT '' COMMENT '申请人', - `principals` varchar(256) NOT NULL DEFAULT '' COMMENT '负责人', - `description` text COMMENT '备注信息', - `order_status` int(16) NOT NULL DEFAULT '0' COMMENT '工单状态', - `approver` varchar(128) NOT NULL DEFAULT '' COMMENT '审批人', - `opinion` varchar(256) NOT NULL DEFAULT '' COMMENT '审批意见', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态,0标识有效,-1无效', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic申请工单'; - -CREATE TABLE `region` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `region_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'Region名称', - `broker_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'Broker列表', - `level` int(16) NOT NULL DEFAULT '0' COMMENT 'Region重要等级, 0级普通, 1极重要,2级极重要', - `operator` varchar(45) NOT NULL DEFAULT '' COMMENT '操作人', - `description` text COMMENT '备注说明', - `status` int(11) NOT NULL DEFAULT '0' COMMENT '状态,0正常,-1废弃,1容量已满', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_id_region_name` (`cluster_id`,`region_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Region信息表'; - -CREATE TABLE `topic` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称', - `applicant` varchar(256) NOT NULL DEFAULT '' COMMENT '申请人', - `principals` varchar(256) NOT NULL DEFAULT '' COMMENT '负责人', - `description` text COMMENT '备注信息', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '0标识使用中,-1标识已废弃', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_id_topic_name` (`cluster_id`,`topic_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic信息表'; - - -CREATE TABLE `topic_favorite` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `username` varchar(64) NOT NULL DEFAULT '' COMMENT '用户名', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '删除标记, 0表示未删除, -1表示删除', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_username_cluster_id_topic_name` (`username`,`cluster_id`,`topic_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户收藏的Topic表'; - -CREATE TABLE `topic_metrics` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒进入消息条数', - `bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流入', - `bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流出', - `bytes_rejected` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒拒绝字节数', - `total_produce_requests` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒请求数', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (`id`), - KEY `idx_cluster_id_topic_name_gmt_create` (`cluster_id`,`topic_name`,`gmt_create`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='TopicMetrics表'; \ No newline at end of file diff --git a/doc/create_postgresql_table.sql b/doc/create_postgresql_table.sql deleted file mode 100644 index 6d03c005..00000000 --- a/doc/create_postgresql_table.sql +++ /dev/null @@ -1,325 +0,0 @@ --- CREATE DATABASE kafka_manager; --- \c kafka_manager; -SET TIME ZONE 'Asia/Chongqing'; -SET CLIENT_ENCODING TO 'UTF-8'; - -CREATE OR REPLACE FUNCTION on_update_timestamp() RETURNS TRIGGER AS -$$ -BEGIN - new.gmt_modify = current_timestamp; - return new; -END; -$$ LANGUAGE plpgsql; - --- 账号表 -CREATE TABLE account -( - id bigserial NOT NULL, -- 'ID', - username varchar(64) NOT NULL UNIQUE DEFAULT '', -- '用户名', - password varchar(128) NOT NULL DEFAULT '', -- '密码', - role int NOT NULL DEFAULT 0, -- '角色类型, 0:普通用户', - status int NOT NULL DEFAULT 0, -- '0标识使用中,-1标识已废弃', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间', - CONSTRAINT account_pk PRIMARY KEY (id) -); -CREATE UNIQUE INDEX account_uniq_username ON account (username); -INSERT INTO account(username, password, role) -VALUES ('admin', '21232f297a57a5a743894a0e4a801fc3', 2); -CREATE TRIGGER account_trig_gmt_modify - BEFORE UPDATE - ON account - FOR EACH ROW -EXECUTE PROCEDURE on_update_timestamp(); - --- 告警规则表 -CREATE TABLE alarm_rule -( - id bigserial, -- '自增ID', - alarm_name varchar(128) NOT NULL DEFAULT '', -- '告警名字', - strategy_expressions text, -- '表达式', - strategy_filters text, -- '过滤条件', - strategy_actions text, -- '响应', - principals varchar(512) NOT NULL DEFAULT '', -- '负责人', - status int2 NOT NULL DEFAULT 1, -- '-1:逻辑删除, 0:关闭, 1:正常', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间', - CONSTRAINT alarm_rule_pk PRIMARY KEY (id) -); -CREATE UNIQUE INDEX alarm_rule_uniq_alarm_name ON alarm_rule (alarm_name); -CREATE TRIGGER alarm_rule_trig_gmt_modify - BEFORE UPDATE - ON alarm_rule - FOR EACH ROW -EXECUTE PROCEDURE on_update_timestamp(); - --- Broker信息表 -CREATE TABLE broker -( - id bigserial, -- 'id', - cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID', - broker_id int NOT NULL DEFAULT '-1', -- 'BrokerID', - host varchar(128) NOT NULL DEFAULT '', -- 'Broker主机名', - port int NOT NULL DEFAULT '-1', -- 'Broker端口', - timestamp bigint NOT NULL DEFAULT '-1', -- '启动时间', - status int NOT NULL DEFAULT '0', -- '状态0有效,-1无效', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间', - CONSTRAINT broker_pk PRIMARY KEY (id) -); -CREATE UNIQUE INDEX broker_uniq_cluster_id_broker_id ON broker (cluster_id, broker_id); -CREATE TRIGGER broker_trig_gmt_modify - BEFORE UPDATE - ON broker - FOR EACH ROW -EXECUTE PROCEDURE on_update_timestamp(); - --- BrokerMetric信息表 -CREATE TABLE broker_metrics -( - id bigserial, -- '自增id', - cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID', - broker_id int NOT NULL DEFAULT '-1', -- 'BrokerID', - bytes_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒字节流入', - bytes_out decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒字节流出', - bytes_rejected decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒被拒绝字节数', - messages_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒消息数流入', - fail_fetch_request decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒消费失败数', - fail_produce_request decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒失败生产数', - fetch_consumer_request decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒消费请求数', - produce_request decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒生产数', - request_handler_idl_percent decimal(53, 2) NOT NULL DEFAULT '0.00', -- '请求处理器繁忙百分比', - network_processor_idl_percent decimal(53, 2) NOT NULL DEFAULT '0.00', -- '网络处理器繁忙百分比', - request_queue_size bigint NOT NULL DEFAULT '0', -- '请求列表大小', - response_queue_size bigint NOT NULL DEFAULT '0', -- '响应列表大小', - log_flush_time decimal(53, 2) NOT NULL DEFAULT '0.00', -- '刷日志时间', - total_time_produce_mean decimal(53, 2) NOT NULL DEFAULT '0.00', -- 'produce请求处理总时间-平均值', - total_time_produce_99th decimal(53, 2) NOT NULL DEFAULT '0.00', -- 'produce请求处理总时间-99分位', - total_time_fetch_consumer_mean decimal(53, 2) NOT NULL DEFAULT '0.00', -- 'fetch请求总时间-平均值', - total_time_fetch_consumer_99th decimal(53, 2) NOT NULL DEFAULT '0.00', -- 'fetch请求总时间-99分位', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - CONSTRAINT broker_metrics_pk PRIMARY KEY (id) -); -CREATE INDEX broker_metrics_idx_cluster_id_broker_id_gmt_create ON broker_metrics (cluster_id, broker_id, gmt_create); - --- Cluster表 -CREATE TABLE cluster -( - id bigserial, -- '集群ID', - cluster_name varchar(128) NOT NULL DEFAULT '', -- '集群名称', - zookeeper varchar(512) NOT NULL DEFAULT '', -- 'ZK地址', - bootstrap_servers varchar(512) NOT NULL DEFAULT '', -- 'Server地址', - kafka_version varchar(32) NOT NULL DEFAULT '', -- 'Kafka版本', - alarm_flag int2 NOT NULL DEFAULT '0', -- '0:不开启告警, 1开启告警', - security_protocol varchar(512) NOT NULL DEFAULT '', -- '安全协议', - sasl_mechanism varchar(512) NOT NULL DEFAULT '', -- '安全机制', - sasl_jaas_config varchar(512) NOT NULL DEFAULT '', -- 'Jaas配置', - status int2 NOT NULL DEFAULT '0', -- '删除标记, 0表示未删除, -1表示删除', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间', - CONSTRAINT cluster_pk PRIMARY KEY (id) -); -CREATE UNIQUE INDEX cluster_uniq_cluster_name ON cluster (cluster_name); -CREATE TRIGGER cluster_trig_gmt_modify - BEFORE UPDATE - ON cluster - FOR EACH ROW -EXECUTE PROCEDURE on_update_timestamp(); - --- ClusterMetrics信息 -CREATE TABLE cluster_metrics -( - id bigserial, -- '自增id', - cluster_id bigint NOT NULL DEFAULT '0', -- '集群ID', - topic_num int NOT NULL DEFAULT '0', -- 'Topic数', - partition_num int NOT NULL DEFAULT '0', -- '分区数', - broker_num int NOT NULL DEFAULT '0', -- 'Broker数', - bytes_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒流入(B)', - bytes_out decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒流出(B)', - bytes_rejected decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒拒绝(B)', - messages_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒消息数(条)', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - CONSTRAINT cluster_metrics_pk PRIMARY KEY (id) -); -CREATE INDEX cluster_metrics_idx_cluster_id_gmt_create ON cluster_metrics (cluster_id, gmt_create); - --- Controller历史变更记录表 -CREATE TABLE controller -( - id bigserial, -- '自增id', - cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID', - broker_id int NOT NULL DEFAULT '-1', -- 'BrokerId', - host varchar(256) NOT NULL DEFAULT '', -- '主机名', - timestamp bigint NOT NULL DEFAULT '-1', -- 'Controller变更时间', - version int NOT NULL DEFAULT '-1', -- 'Controller格式版本', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - CONSTRAINT controller_pk PRIMARY KEY (id) -); -CREATE UNIQUE INDEX controller_uniq_cluster_id_broker_id_timestamp ON controller (cluster_id, broker_id, timestamp); - --- Topic迁移信息 -CREATE TABLE migration_task -( - id bigserial, -- '自增id', - cluster_id bigint NOT NULL DEFAULT '0', -- '集群ID', - topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称', - reassignment_json text, -- '任务参数', - real_throttle bigint NOT NULL DEFAULT '0', -- '实际限流值(B/s)', - operator varchar(128) NOT NULL DEFAULT '', -- '操作人', - description varchar(256) NOT NULL DEFAULT '', -- '备注说明', - status int NOT NULL DEFAULT '0', -- '任务状态', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '任务创建时间', - gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '任务修改时间', - CONSTRAINT migration_task_pk PRIMARY KEY (id) -); -CREATE TRIGGER migration_task_trig_gmt_modify - BEFORE UPDATE - ON migration_task - FOR EACH ROW -EXECUTE PROCEDURE on_update_timestamp(); - -CREATE TABLE operation_history -( - id bigserial, -- 'id', - cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID', - topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称', - operator varchar(128) NOT NULL DEFAULT '', -- '操作人', - operation varchar(256) NOT NULL DEFAULT '', -- '操作描述', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - PRIMARY KEY (id) -); ---='操作记录表'; - --- 分区申请工单 -CREATE TABLE order_partition -( - id bigserial, -- 'id', - cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID', - cluster_name varchar(128) NOT NULL DEFAULT '', -- '集群名称', - topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称', - applicant varchar(128) NOT NULL DEFAULT '', -- '申请人', - partition_num int NOT NULL DEFAULT '0', -- '分区数', - broker_list varchar(128) NOT NULL DEFAULT '', -- 'Broker列表', - peak_bytes_in bigint NOT NULL DEFAULT '0', -- '峰值流量', - description text, -- '备注信息', - order_status int NOT NULL DEFAULT '0', -- '工单状态', - approver varchar(128) NOT NULL DEFAULT '', -- '审批人', - opinion varchar(256) NOT NULL DEFAULT '', -- '审批意见', - status int NOT NULL DEFAULT '0', -- '状态,0标识有效,-1无效', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间', - CONSTRAINT order_partition_pk PRIMARY KEY (id) -); -CREATE TRIGGER order_partition_trig_gmt_modify - BEFORE UPDATE - ON order_partition - FOR EACH ROW -EXECUTE PROCEDURE on_update_timestamp(); - --- Topic申请工单 -CREATE TABLE order_topic -( - id bigserial, -- 'ID', - cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID', - cluster_name varchar(128) NOT NULL DEFAULT '', -- '集群名称', - topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称', - retention_time bigint NOT NULL DEFAULT '-1', -- '保留时间(ms)', - partition_num int NOT NULL DEFAULT '-1', -- '分区数', - replica_num int NOT NULL DEFAULT '-1', -- '副本数', - regions varchar(128) NOT NULL DEFAULT '', -- 'RegionId列表', - brokers varchar(128) NOT NULL DEFAULT '', -- 'Broker列表', - peak_bytes_in bigint NOT NULL DEFAULT '0', -- '峰值流入流量(KB)', - applicant varchar(128) NOT NULL DEFAULT '', -- '申请人', - principals varchar(256) NOT NULL DEFAULT '', -- '负责人', - description text, -- '备注信息', - order_status int NOT NULL DEFAULT '0', -- '工单状态', - approver varchar(128) NOT NULL DEFAULT '', -- '审批人', - opinion varchar(256) NOT NULL DEFAULT '', -- '审批意见', - status int NOT NULL DEFAULT '0', -- '状态,0标识有效,-1无效', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间', - CONSTRAINT order_topic_pk PRIMARY KEY (id) -); -CREATE TRIGGER order_topic_trig_gmt_modify - BEFORE UPDATE - ON order_topic - FOR EACH ROW -EXECUTE PROCEDURE on_update_timestamp(); - --- Region信息表 -CREATE TABLE region -( - id bigserial, -- 'id', - cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID', - region_name varchar(128) NOT NULL DEFAULT '', -- 'Region名称', - broker_list varchar(256) NOT NULL DEFAULT '', -- 'Broker列表', - level int NOT NULL DEFAULT '0', -- 'Region重要等级, 0级普通, 1极重要,2级极重要', - operator varchar(45) NOT NULL DEFAULT '', -- '操作人', - description text, -- '备注说明', - status int NOT NULL DEFAULT '0', -- '状态,0正常,-1废弃,1容量已满', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间', - CONSTRAINT region_pk PRIMARY KEY (id) -); -CREATE UNIQUE INDEX region_uniq_cluster_id_region_name ON region (cluster_id, region_name); -CREATE TRIGGER region_trig_gmt_modify - BEFORE UPDATE - ON region - FOR EACH ROW -EXECUTE PROCEDURE on_update_timestamp(); - --- Topic信息表 -CREATE TABLE topic -( - id bigserial, -- 'ID', - cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID', - topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称', - applicant varchar(256) NOT NULL DEFAULT '', -- '申请人', - principals varchar(256) NOT NULL DEFAULT '', -- '负责人', - description text, -- '备注信息', - status int NOT NULL DEFAULT '0', -- '0标识使用中,-1标识已废弃', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间', - CONSTRAINT topic_pk PRIMARY KEY (id) -); --=''; -CREATE UNIQUE INDEX topic_uniq_cluster_id_topic_name ON topic (cluster_id, topic_name); -CREATE TRIGGER topic_trig_gmt_modify - BEFORE UPDATE - ON topic - FOR EACH ROW -EXECUTE PROCEDURE on_update_timestamp(); - --- 用户收藏的Topic表 -CREATE TABLE topic_favorite -( - id bigserial, -- '自增Id', - username varchar(64) NOT NULL DEFAULT '', -- '用户名', - cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID', - topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称', - status int NOT NULL DEFAULT '0', -- '删除标记, 0表示未删除, -1表示删除', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间', - CONSTRAINT topic_favorite_pk PRIMARY KEY (id) -); -CREATE UNIQUE INDEX topic_favorite_uniq_username_cluster_id_topic_name ON topic_favorite (username, cluster_id, topic_name); -CREATE TRIGGER topic_favorite_trig_gmt_modify - BEFORE UPDATE - ON topic_favorite - FOR EACH ROW -EXECUTE PROCEDURE on_update_timestamp(); - --- TopicMetrics表 -CREATE TABLE topic_metrics -( - id bigserial, -- '自增id', - cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID', - topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称', - messages_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒进入消息条数', - bytes_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒字节流入', - bytes_out decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒字节流出', - bytes_rejected decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒拒绝字节数', - total_produce_requests decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒请求数', - gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间', - CONSTRAINT topic_metrics_pk PRIMARY KEY (id) -); -CREATE INDEX topic_metrics_idx_cluster_id_topic_name_gmt_create ON topic_metrics (cluster_id, topic_name, gmt_create); diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 10c69adf..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: '2' -services: - mysqldbserver: - container_name: mysqldbserver - image: mysql:5.7 - build: - context: . - dockerfile: docker/mysql/Dockerfile - ports: - - "3306:3306" - command: [ - 'mysqld', - '--character-set-server=utf8', - '--collation-server=utf8_general_ci', - '--default-time-zone=+8:00' - ] - environment: - MYSQL_ROOT_PASSWORD: 12345678 - MYSQL_DATABASE: kafka_manager - MYSQL_USER: admin - MYSQL_PASSWORD: 12345678 - restart: always - kafka-manager-web: - container_name: kafka-manager-web - build: - context: . - dockerfile: Dockerfile - ports: - - "8080:8080" - links: - - mysqldbserver - restart: always \ No newline at end of file diff --git a/docker/kafka-manager/Dockerfile b/docker/kafka-manager/Dockerfile deleted file mode 100644 index de8d2f25..00000000 --- a/docker/kafka-manager/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM java:8 -MAINTAINER xuzhengxi -ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 -ADD ../../web/target/kafka-manager-web-1.1.0-SNAPSHOT.jar kafka-manager-web.jar -ADD ./application.yml application.yml -ENTRYPOINT ["java","-jar","/kafka-manager-web.jar","--spring.config.location=./application.yml"] -EXPOSE 8080 \ No newline at end of file diff --git a/docker/kafka-manager/application-standalone.yml b/docker/kafka-manager/application-standalone.yml deleted file mode 100644 index 581170bc..00000000 --- a/docker/kafka-manager/application-standalone.yml +++ /dev/null @@ -1,32 +0,0 @@ -server: - port: 8080 - tomcat: - accept-count: 100 - max-connections: 1000 - max-threads: 20 - min-spare-threads: 20 - -spring: - application: - name: kafkamanager - datasource: - kafka-manager: - jdbc-url: jdbc:mysql://mysqldbserver:3306/kafka_manager?characterEncoding=UTF-8&serverTimezone=GMT%2B8 - username: admin - password: 12345678 - driver-class-name: org.mariadb.jdbc.Driver - main: - allow-bean-definition-overriding: true - - profiles: - active: dev - -logging: - config: classpath:logback-spring.xml - -# kafka监控 -kafka-monitor: - enabled: true - notify-kafka: - cluster-id: 95 - topic-name: kmo_monitor diff --git a/docker/kafka-manager/application.yml b/docker/kafka-manager/application.yml deleted file mode 100644 index 581170bc..00000000 --- a/docker/kafka-manager/application.yml +++ /dev/null @@ -1,32 +0,0 @@ -server: - port: 8080 - tomcat: - accept-count: 100 - max-connections: 1000 - max-threads: 20 - min-spare-threads: 20 - -spring: - application: - name: kafkamanager - datasource: - kafka-manager: - jdbc-url: jdbc:mysql://mysqldbserver:3306/kafka_manager?characterEncoding=UTF-8&serverTimezone=GMT%2B8 - username: admin - password: 12345678 - driver-class-name: org.mariadb.jdbc.Driver - main: - allow-bean-definition-overriding: true - - profiles: - active: dev - -logging: - config: classpath:logback-spring.xml - -# kafka监控 -kafka-monitor: - enabled: true - notify-kafka: - cluster-id: 95 - topic-name: kmo_monitor diff --git a/docker/mysql/Dockerfile b/docker/mysql/Dockerfile deleted file mode 100644 index b2e4afed..00000000 --- a/docker/mysql/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM mysql:5.7 -MAINTAINER xuzhengxi -COPY ./docker/mysql/create_mysql_table.sql /docker-entrypoint-initdb.d/ \ No newline at end of file diff --git a/docker/mysql/create_mysql_table.sql b/docker/mysql/create_mysql_table.sql deleted file mode 100644 index 9a66ac67..00000000 --- a/docker/mysql/create_mysql_table.sql +++ /dev/null @@ -1,243 +0,0 @@ -CREATE DATABASE IF NOT EXISTS `kafka_manager`; - -USE `kafka_manager`; - -CREATE TABLE `account` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', - `username` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户名', - `password` varchar(128) NOT NULL DEFAULT '' COMMENT '密码', - `role` int(16) NOT NULL DEFAULT '0' COMMENT '角色类型, 0:普通用户', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '0标识使用中,-1标识已废弃', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_username` (`username`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='账号表'; -INSERT INTO account(username, password, role) VALUES ('admin', '21232f297a57a5a743894a0e4a801fc3', 2); - - -CREATE TABLE `alarm_rule` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID', - `alarm_name` varchar(128) NOT NULL DEFAULT '' COMMENT '告警名字', - `strategy_expressions` text COMMENT '表达式', - `strategy_filters` text COMMENT '过滤条件', - `strategy_actions` text COMMENT '响应', - `principals` varchar(512) NOT NULL DEFAULT '' COMMENT '负责人', - `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '-1:逻辑删除, 0:关闭, 1:正常', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_alarm_name` (`alarm_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='告警规则表'; - - -CREATE TABLE `broker` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerID', - `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'Broker主机名', - `port` int(32) NOT NULL DEFAULT '-1' COMMENT 'Broker端口', - `timestamp` bigint(128) NOT NULL DEFAULT '-1' COMMENT '启动时间', - `status` int(11) NOT NULL DEFAULT '0' COMMENT '状态0有效,-1无效', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_id_broker_id` (`cluster_id`,`broker_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Broker信息表'; - - -CREATE TABLE `broker_metrics` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerID', - `bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流入', - `bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流出', - `bytes_rejected` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒被拒绝字节数', - `messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消息数流入', - `fail_fetch_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消费失败数', - `fail_produce_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒失败生产数', - `fetch_consumer_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消费请求数', - `produce_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒生产数', - `request_handler_idl_percent` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '请求处理器繁忙百分比', - `network_processor_idl_percent` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '网络处理器繁忙百分比', - `request_queue_size` bigint(20) NOT NULL DEFAULT '0' COMMENT '请求列表大小', - `response_queue_size` bigint(20) NOT NULL DEFAULT '0' COMMENT '响应列表大小', - `log_flush_time` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '刷日志时间', - `total_time_produce_mean` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'produce请求处理总时间-平均值', - `total_time_produce_99th` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'produce请求处理总时间-99分位', - `total_time_fetch_consumer_mean` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'fetch请求总时间-平均值', - `total_time_fetch_consumer_99th` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'fetch请求总时间-99分位', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (`id`), - KEY `idx_cluster_id_broker_id_gmt_create` (`cluster_id`,`broker_id`,`gmt_create`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='BrokerMetric信息表'; - - -CREATE TABLE `cluster` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '集群ID', - `cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称', - `zookeeper` varchar(512) NOT NULL DEFAULT '' COMMENT 'ZK地址', - `bootstrap_servers` varchar(512) NOT NULL DEFAULT '' COMMENT 'Server地址', - `kafka_version` varchar(32) NOT NULL DEFAULT '' COMMENT 'Kafka版本', - `alarm_flag` int(4) NOT NULL DEFAULT '0' COMMENT '0:不开启告警, 1开启告警', - `security_protocol` varchar(512) NOT NULL DEFAULT '' COMMENT '安全协议', - `sasl_mechanism` varchar(512) NOT NULL DEFAULT '' COMMENT '安全机制', - `sasl_jaas_config` varchar(512) NOT NULL DEFAULT '' COMMENT 'Jaas配置', - `status` int(4) NOT NULL DEFAULT '0' COMMENT '删除标记, 0表示未删除, -1表示删除', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_name` (`cluster_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Cluster表'; - - -CREATE TABLE `cluster_metrics` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群ID', - `topic_num` int(11) NOT NULL DEFAULT '0' COMMENT 'Topic数', - `partition_num` int(11) NOT NULL DEFAULT '0' COMMENT '分区数', - `broker_num` int(11) NOT NULL DEFAULT '0' COMMENT 'Broker数', - `bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒流入(B)', - `bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒流出(B)', - `bytes_rejected` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒拒绝(B)', - `messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消息数(条)', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (`id`), - KEY `idx_cluster_id_gmt_create` (`cluster_id`,`gmt_create`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ClusterMetrics信息'; - - -CREATE TABLE `controller` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerId', - `host` varchar(256) NOT NULL DEFAULT '' COMMENT '主机名', - `timestamp` bigint(20) NOT NULL DEFAULT '-1' COMMENT 'Controller变更时间', - `version` int(11) NOT NULL DEFAULT '-1' COMMENT 'Controller格式版本', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_id_broker_id_timestamp` (`cluster_id`,`broker_id`,`timestamp`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Controller历史变更记录表'; - -CREATE TABLE `migration_task` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群ID', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `reassignment_json` text COMMENT '任务参数', - `real_throttle` bigint(20) NOT NULL DEFAULT '0' COMMENT '实际限流值(B/s)', - `operator` varchar(128) NOT NULL DEFAULT '' COMMENT '操作人', - `description` varchar(256) NOT NULL DEFAULT '' COMMENT '备注说明', - `status` int(11) NOT NULL DEFAULT '0' COMMENT '任务状态', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic迁移信息'; - -CREATE TABLE `operation_history` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `operator` varchar(128) NOT NULL DEFAULT '' COMMENT '操作人', - `operation` varchar(256) NOT NULL DEFAULT '' COMMENT '操作描述', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='操作记录表'; - - -CREATE TABLE `order_partition` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `broker_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'Broker列表, 逗号分割', - `partition_num` int(11) NOT NULL DEFAULT 0 COMMENT '新增分区数', - `applicant` varchar(128) NOT NULL DEFAULT '' COMMENT '申请人', - `peak_bytes_in` bigint(20) NOT NULL DEFAULT '0' COMMENT '峰值流量', - `description` text COMMENT '备注信息', - `order_status` int(16) NOT NULL DEFAULT '0' COMMENT '工单状态', - `approver` varchar(128) NOT NULL DEFAULT '' COMMENT '审批人', - `opinion` varchar(256) NOT NULL DEFAULT '' COMMENT '审批意见', - `status` int(11) NOT NULL DEFAULT '0' COMMENT '状态,0标识有效,-1无效', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='分区申请工单'; - -CREATE TABLE `order_topic` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `retention_time` bigint(20) NOT NULL DEFAULT '-1' COMMENT '保留时间(ms)', - `partition_num` int(16) NOT NULL DEFAULT '-1' COMMENT '分区数', - `replica_num` int(16) NOT NULL DEFAULT '-1' COMMENT '副本数', - `regions` varchar(128) NOT NULL DEFAULT '' COMMENT 'RegionId列表', - `brokers` varchar(128) NOT NULL DEFAULT '' COMMENT 'Broker列表', - `peak_bytes_in` bigint(20) NOT NULL DEFAULT '0' COMMENT '峰值流入流量(KB)', - `applicant` varchar(128) NOT NULL DEFAULT '' COMMENT '申请人', - `principals` varchar(256) NOT NULL DEFAULT '' COMMENT '负责人', - `description` text COMMENT '备注信息', - `order_status` int(16) NOT NULL DEFAULT '0' COMMENT '工单状态', - `approver` varchar(128) NOT NULL DEFAULT '' COMMENT '审批人', - `opinion` varchar(256) NOT NULL DEFAULT '' COMMENT '审批意见', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态,0标识有效,-1无效', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic申请工单'; - -CREATE TABLE `region` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `region_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'Region名称', - `broker_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'Broker列表', - `level` int(16) NOT NULL DEFAULT '0' COMMENT 'Region重要等级, 0级普通, 1极重要,2级极重要', - `operator` varchar(45) NOT NULL DEFAULT '' COMMENT '操作人', - `description` text COMMENT '备注说明', - `status` int(11) NOT NULL DEFAULT '0' COMMENT '状态,0正常,-1废弃,1容量已满', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_id_region_name` (`cluster_id`,`region_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Region信息表'; - -CREATE TABLE `topic` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称', - `applicant` varchar(256) NOT NULL DEFAULT '' COMMENT '申请人', - `principals` varchar(256) NOT NULL DEFAULT '' COMMENT '负责人', - `description` text COMMENT '备注信息', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '0标识使用中,-1标识已废弃', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_id_topic_name` (`cluster_id`,`topic_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic信息表'; - - -CREATE TABLE `topic_favorite` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `username` varchar(64) NOT NULL DEFAULT '' COMMENT '用户名', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '删除标记, 0表示未删除, -1表示删除', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_username_cluster_id_topic_name` (`username`,`cluster_id`,`topic_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户收藏的Topic表'; - -CREATE TABLE `topic_metrics` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒进入消息条数', - `bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流入', - `bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流出', - `bytes_rejected` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒拒绝字节数', - `total_produce_requests` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒请求数', - `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (`id`), - KEY `idx_cluster_id_topic_name_gmt_create` (`cluster_id`,`topic_name`,`gmt_create`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='TopicMetrics表'; \ No newline at end of file diff --git a/doc/assets/images/common/arch.png b/docs/assets/images/common/arch.png similarity index 100% rename from doc/assets/images/common/arch.png rename to docs/assets/images/common/arch.png diff --git a/doc/assets/images/common/dingding_group.jpg b/docs/assets/images/common/dingding_group.jpg similarity index 100% rename from doc/assets/images/common/dingding_group.jpg rename to docs/assets/images/common/dingding_group.jpg diff --git a/doc/assets/images/common/logo_name.png b/docs/assets/images/common/logo_name.png similarity index 100% rename from doc/assets/images/common/logo_name.png rename to docs/assets/images/common/logo_name.png diff --git a/docs/create_mysql_table.sql b/docs/create_mysql_table.sql new file mode 100644 index 00000000..9b4bfe35 --- /dev/null +++ b/docs/create_mysql_table.sql @@ -0,0 +1,577 @@ +-- +-- Table structure for table `account` +-- + +-- DROP TABLE IF EXISTS `account`; +CREATE TABLE `account` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `username` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户名', + `password` varchar(128) NOT NULL DEFAULT '' COMMENT '密码', + `role` tinyint(8) NOT NULL DEFAULT '0' COMMENT '角色类型, 0:普通用户 1:研发 2:运维', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '0标识使用中,-1标识已废弃', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_username` (`username`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='账号表'; +INSERT INTO account(username, password, role) VALUES ('admin', '21232f297a57a5a743894a0e4a801fc3', 2); + +-- +-- Table structure for table `app` +-- + +-- DROP TABLE IF EXISTS `app`; +CREATE TABLE `app` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `app_id` varchar(128) NOT NULL DEFAULT '' COMMENT '应用id', + `name` varchar(192) NOT NULL DEFAULT '' COMMENT '应用名称', + `password` varchar(256) NOT NULL DEFAULT '' COMMENT '应用密码', + `type` int(11) NOT NULL DEFAULT '0' COMMENT '类型, 0:普通用户, 1:超级用户', + `applicant` varchar(64) NOT NULL DEFAULT '' COMMENT '申请人', + `principals` text COMMENT '应用负责人', + `description` text COMMENT '应用描述', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_name` (`name`), + UNIQUE KEY `uniq_app_id` (`app_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='应用信息'; +INSERT INTO app(app_id, name, password, type, applicant, principals, description) VALUES ('km-admin-tmp', 'km-admin-tmp', '123456', 0, 'admin', 'admin', '临时应用'); + + +-- +-- Table structure for table `authority` +-- + +-- DROP TABLE IF EXISTS `authority`; +CREATE TABLE `authority` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `app_id` varchar(128) NOT NULL DEFAULT '' COMMENT '应用id', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'topic名称', + `access` int(11) NOT NULL DEFAULT '0' COMMENT '0:无权限, 1:读, 2:写, 3:读写', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_app_id_cluster_id_topic_name` (`app_id`,`cluster_id`,`topic_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权限信息(kafka-manager)'; + +-- +-- Table structure for table `broker` +-- + +-- DROP TABLE IF EXISTS `broker`; +CREATE TABLE `broker` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `broker_id` int(16) NOT NULL DEFAULT '-1' COMMENT 'brokerid', + `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'broker主机名', + `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'broker端口', + `timestamp` bigint(20) NOT NULL DEFAULT '-1' COMMENT '启动时间', + `max_avg_bytes_in` bigint(20) NOT NULL DEFAULT '-1' COMMENT '峰值的均值流量', + `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'broker版本', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 0有效,-1无效', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_id_broker_id` (`cluster_id`,`broker_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='broker信息表'; + +-- +-- Table structure for table `broker_metrics` +-- + +-- DROP TABLE IF EXISTS `broker_metrics`; +CREATE TABLE `broker_metrics` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `broker_id` int(16) NOT NULL DEFAULT '-1' COMMENT 'brokerid', + `metrics` text COMMENT '指标', + `messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消息数流入', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_cluster_id_broker_id_gmt_create` (`cluster_id`,`broker_id`,`gmt_create`), + KEY `idx_gmt_create` (`gmt_create`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='broker-metric信息表'; + +-- +-- Table structure for table `cluster` +-- + +-- DROP TABLE IF EXISTS `cluster`; +CREATE TABLE `cluster` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '集群id', + `cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称', + `zookeeper` varchar(512) NOT NULL DEFAULT '' COMMENT 'zk地址', + `bootstrap_servers` varchar(512) NOT NULL DEFAULT '' COMMENT 'server地址', + `kafka_version` varchar(32) NOT NULL DEFAULT '' COMMENT 'kafka版本', + `idc` varchar(64) NOT NULL DEFAULT '' COMMENT '数据中心', + `mode` tinyint(4) NOT NULL DEFAULT '0' COMMENT '集群模式, 0:共享, 1:独享, 2:独立', + `security_properties` text COMMENT '安全认证参数', + `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT ' 监控标记, 0表示未监控, 1表示监控中', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_name` (`cluster_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='cluster信息表'; + +-- +-- Table structure for table `cluster_metrics` +-- + +-- DROP TABLE IF EXISTS `cluster_metrics`; +CREATE TABLE `cluster_metrics` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `metrics` text COMMENT '指标', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_cluster_id_gmt_create` (`cluster_id`,`gmt_create`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='clustermetrics信息'; + +-- +-- Table structure for table `cluster_tasks` +-- + +-- DROP TABLE IF EXISTS `cluster_tasks`; +CREATE TABLE `cluster_tasks` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `uuid` varchar(128) NOT NULL DEFAULT '' COMMENT '任务UUID', + `cluster_id` bigint(128) NOT NULL DEFAULT '-1' COMMENT '集群id', + `task_type` varchar(128) NOT NULL DEFAULT '' COMMENT '任务类型', + `kafka_package` text COMMENT 'kafka包', + `kafka_package_md5` varchar(128) NOT NULL DEFAULT '' COMMENT 'kafka包的md5', + `server_properties` text COMMENT 'kafkaserver配置', + `server_properties_md5` varchar(128) NOT NULL DEFAULT '' COMMENT '配置文件的md5', + `agent_task_id` bigint(128) NOT NULL DEFAULT '-1' COMMENT '任务id', + `agent_rollback_task_id` bigint(128) NOT NULL DEFAULT '-1' COMMENT '回滚任务id', + `host_list` text COMMENT '升级的主机', + `pause_host_list` text COMMENT '暂停点', + `rollback_host_list` text COMMENT '回滚机器列表', + `rollback_pause_host_list` text COMMENT '回滚暂停机器列表', + `operator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人', + `task_status` int(11) NOT NULL DEFAULT '0' COMMENT '任务状态', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='集群任务(集群升级部署)'; + +-- +-- Table structure for table `config` +-- + +-- DROP TABLE IF EXISTS `config`; +CREATE TABLE `config` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `config_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '配置key', + `config_value` text COMMENT '配置value', + `config_description` text COMMENT '备注说明', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '0标识使用中,-1标识已废弃', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_config_key` (`config_key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='配置表'; + +-- +-- Table structure for table `controller` +-- + +-- DROP TABLE IF EXISTS `controller`; +CREATE TABLE `controller` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `broker_id` int(16) NOT NULL DEFAULT '-1' COMMENT 'brokerid', + `host` varchar(256) NOT NULL DEFAULT '' COMMENT '主机名', + `timestamp` bigint(20) NOT NULL DEFAULT '-1' COMMENT 'controller变更时间', + `version` int(16) NOT NULL DEFAULT '-1' COMMENT 'controller格式版本', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_id_broker_id_timestamp` (`cluster_id`,`broker_id`,`timestamp`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='controller记录表'; + +-- +-- Table structure for table `gateway_config` +-- + +-- DROP TABLE IF EXISTS `gateway_config`; +CREATE TABLE `gateway_config` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `type` varchar(128) NOT NULL DEFAULT '' COMMENT '配置类型', + `name` varchar(128) NOT NULL DEFAULT '' COMMENT '配置名称', + `value` text COMMENT '配置值', + `version` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '版本信息', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_type_name` (`type`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='gateway配置'; + +-- +-- Table structure for table `heartbeat` +-- + +-- DROP TABLE IF EXISTS `heartbeat`; +CREATE TABLE `heartbeat` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `ip` varchar(128) NOT NULL DEFAULT '' COMMENT '主机ip', + `hostname` varchar(256) NOT NULL DEFAULT '' COMMENT '主机名', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_ip` (`ip`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='心跳信息'; + +-- +-- Table structure for table `kafka_acl` +-- + +-- DROP TABLE IF EXISTS `kafka_acl`; +CREATE TABLE `kafka_acl` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `app_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户id', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic名称', + `access` int(11) NOT NULL DEFAULT '0' COMMENT '0:无权限, 1:读, 2:写, 3:读写', + `operation` int(11) NOT NULL DEFAULT '0' COMMENT '0:创建, 1:更新 2:删除, 以最新的一条数据为准', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权限信息(kafka-broker)'; + +-- +-- Table structure for table `kafka_bill` +-- + +-- DROP TABLE IF EXISTS `kafka_bill`; +CREATE TABLE `kafka_bill` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic名称', + `principal` varchar(64) NOT NULL DEFAULT '' COMMENT '负责人', + `quota` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '配额, 单位mb/s', + `cost` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '成本, 单位元', + `cost_type` int(16) NOT NULL DEFAULT '0' COMMENT '成本类型, 0:共享集群, 1:独享集群, 2:独立集群', + `gmt_day` varchar(64) NOT NULL DEFAULT '' COMMENT '计价的日期, 例如2019-02-02的计价结果', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_id_topic_name_gmt_day` (`cluster_id`,`topic_name`,`gmt_day`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='kafka账单'; + +-- +-- Table structure for table `kafka_file` +-- + +-- DROP TABLE IF EXISTS `kafka_file`; +CREATE TABLE `kafka_file` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `storage_name` varchar(128) NOT NULL DEFAULT '' COMMENT '存储位置', + `file_name` varchar(128) NOT NULL DEFAULT '' COMMENT '文件名', + `file_md5` varchar(256) NOT NULL DEFAULT '' COMMENT '文件md5', + `file_type` int(16) NOT NULL DEFAULT '-1' COMMENT '0:kafka压缩包, 1:kafkaserver配置', + `description` text COMMENT '备注信息', + `operator` varchar(64) NOT NULL DEFAULT '' COMMENT '创建用户', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态, 0:正常, -1:删除', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_id_file_name_storage_name` (`cluster_id`,`file_name`,`storage_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文件管理'; + +-- +-- Table structure for table `kafka_user` +-- + +-- DROP TABLE IF EXISTS `kafka_user`; +CREATE TABLE `kafka_user` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `app_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '应用id', + `password` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '密码', + `user_type` int(11) NOT NULL DEFAULT '0' COMMENT '0:普通用户, 1:超级用户', + `operation` int(11) NOT NULL DEFAULT '0' COMMENT '0:创建, 1:更新 2:删除, 以最新一条的记录为准', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='kafka用户表'; + +-- +-- Table structure for table `logical_cluster` +-- + +-- DROP TABLE IF EXISTS `logical_cluster`; +CREATE TABLE `logical_cluster` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `name` varchar(192) NOT NULL DEFAULT '' COMMENT '逻辑集群名称', + `mode` int(16) NOT NULL DEFAULT '0' COMMENT '逻辑集群类型, 0:共享集群, 1:独享集群, 2:独立集群', + `app_id` varchar(64) NOT NULL DEFAULT '' COMMENT '所属应用', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `region_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'regionid列表', + `description` text COMMENT '备注说明', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='逻辑集群信息表'; + +-- +-- Table structure for table `monitor_rule` +-- + +-- DROP TABLE IF EXISTS `monitor_rule`; +CREATE TABLE `monitor_rule` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `name` varchar(192) NOT NULL DEFAULT '' COMMENT '告警名称', + `strategy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '监控id', + `app_id` varchar(64) NOT NULL DEFAULT '' COMMENT 'appid', + `operator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='监控规则'; + +-- +-- Table structure for table `operate_record` +-- + +-- DROP TABLE IF EXISTS `operate_record`; +CREATE TABLE `operate_record` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `module_id` int(16) NOT NULL DEFAULT '-1' COMMENT '模块类型, 0:topic, 1:应用, 2:配额, 3:权限, 4:集群, -1:未知', + `operate_id` int(16) NOT NULL DEFAULT '-1' COMMENT '操作类型, 0:新增, 1:删除, 2:修改', + `resource` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic名称、app名称', + `content` text COMMENT '操作内容', + `operator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_module_id_operate_id_operator` (`module_id`,`operate_id`,`operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='操作记录'; + +-- +-- Table structure for table `reassign_task` +-- + +-- DROP TABLE IF EXISTS `reassign_task`; +CREATE TABLE `reassign_task` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `task_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '任务ID', + `name` varchar(256) NOT NULL DEFAULT '' COMMENT '任务名称', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', + `partitions` text COMMENT '分区', + `reassignment_json` text COMMENT '任务参数', + `real_throttle` bigint(20) NOT NULL DEFAULT '0' COMMENT '限流值', + `max_throttle` bigint(20) NOT NULL DEFAULT '0' COMMENT '限流上限', + `min_throttle` bigint(20) NOT NULL DEFAULT '0' COMMENT '限流下限', + `begin_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '开始时间', + `operator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '备注说明', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '任务状态', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', + `original_retention_time` bigint(20) NOT NULL DEFAULT '86400000' COMMENT 'Topic存储时间', + `reassign_retention_time` bigint(20) NOT NULL DEFAULT '86400000' COMMENT '迁移时的存储时间', + `src_brokers` text COMMENT '源Broker', + `dest_brokers` text COMMENT '目标Broker', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='topic迁移信息'; + +-- +-- Table structure for table `region` +-- + +-- DROP TABLE IF EXISTS `region`; +CREATE TABLE `region` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `name` varchar(192) NOT NULL DEFAULT '' COMMENT 'region名称', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `broker_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'broker列表', + `capacity` bigint(20) NOT NULL DEFAULT '0' COMMENT '容量(B/s)', + `real_used` bigint(20) NOT NULL DEFAULT '0' COMMENT '实际使用量(B/s)', + `estimate_used` bigint(20) NOT NULL DEFAULT '0' COMMENT '预估使用量(B/s)', + `description` text COMMENT '备注说明', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态,0正常,1已满', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='region信息表'; + +-- +-- Table structure for table `topic` +-- + +-- DROP TABLE IF EXISTS `topic`; +CREATE TABLE `topic` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic名称', + `app_id` varchar(64) NOT NULL DEFAULT '' COMMENT 'topic所属appid', + `peak_bytes_in` bigint(20) NOT NULL DEFAULT '0' COMMENT '峰值流量', + `description` text COMMENT '备注信息', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_id_topic_name` (`cluster_id`,`topic_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='topic信息表'; + +-- +-- Table structure for table `topic_app_metrics` +-- + +-- DROP TABLE IF EXISTS `topic_app_metrics`; +CREATE TABLE `topic_app_metrics` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic名称', + `app_id` varchar(64) NOT NULL DEFAULT '' COMMENT 'appid', + `metrics` text COMMENT '指标', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_cluster_id_topic_name_app_id_gmt_create` (`cluster_id`,`topic_name`,`app_id`,`gmt_create`), + KEY `idx_gmt_create` (`gmt_create`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='topic app metrics'; + +-- +-- Table structure for table `topic_connections` +-- + +-- DROP TABLE IF EXISTS `topic_connections`; +CREATE TABLE `topic_connections` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `app_id` varchar(64) NOT NULL DEFAULT '' COMMENT '应用id', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic名称', + `type` varchar(16) NOT NULL DEFAULT '' COMMENT 'producer or consumer', + `ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'ip地址', + `client_version` varchar(8) NOT NULL DEFAULT '' COMMENT '客户端版本', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_app_id_cluster_id_topic_name_type_ip_client_version` (`app_id`,`cluster_id`,`topic_name`,`type`,`ip`,`client_version`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='topic连接信息表'; + +-- +-- Table structure for table `topic_expired` +-- + +-- DROP TABLE IF EXISTS `topic_expired`; +CREATE TABLE `topic_expired` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic名称', + `produce_connection_num` bigint(20) NOT NULL DEFAULT '0' COMMENT '发送连接数', + `fetch_connection_num` bigint(20) NOT NULL DEFAULT '0' COMMENT '消费连接数', + `expired_day` bigint(20) NOT NULL DEFAULT '0' COMMENT '过期天数', + `gmt_retain` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '保留截止时间', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '-1:可下线, 0:过期待通知, 1+:已通知待反馈', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_id_topic_name` (`cluster_id`,`topic_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='topic过期信息表'; + +-- +-- Table structure for table `topic_metrics` +-- + +-- DROP TABLE IF EXISTS `topic_metrics`; +CREATE TABLE `topic_metrics` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'topic名称', + `metrics` text COMMENT '指标数据JSON', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_cluster_id_topic_name_gmt_create` (`cluster_id`,`topic_name`,`gmt_create`), + KEY `idx_gmt_create` (`gmt_create`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='topicmetrics表'; + +-- +-- Table structure for table `topic_report` +-- + +-- DROP TABLE IF EXISTS `topic_report`; +CREATE TABLE `topic_report` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic名称', + `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '开始上报时间', + `end_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '结束上报时间', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_id_topic_name` (`cluster_id`,`topic_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='开启jmx采集的topic'; + +-- +-- Table structure for table `topic_request_time_metrics` +-- + +-- DROP TABLE IF EXISTS `topic_request_time_metrics`; +CREATE TABLE `topic_request_time_metrics` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic名称', + `metrics` text COMMENT '指标', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_cluster_id_topic_name_gmt_create` (`cluster_id`,`topic_name`,`gmt_create`), + KEY `idx_gmt_create` (`gmt_create`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='topic请求耗时信息'; + +-- +-- Table structure for table `topic_statistics` +-- + +-- DROP TABLE IF EXISTS `topic_statistics`; +CREATE TABLE `topic_statistics` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic名称', + `offset_sum` bigint(20) NOT NULL DEFAULT '-1' COMMENT 'offset和', + `max_avg_bytes_in` double(53,2) NOT NULL DEFAULT '-1.00' COMMENT '峰值的均值流量', + `gmt_day` varchar(64) NOT NULL DEFAULT '' COMMENT '日期2020-03-30的形式', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `max_avg_messages_in` double(53,2) NOT NULL DEFAULT '-1.00' COMMENT '峰值的均值消息条数', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_id_topic_name_gmt_day` (`cluster_id`,`topic_name`,`gmt_day`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='topic统计信息表'; + +-- +-- Table structure for table `topic_throttled_metrics` +-- + +-- DROP TABLE IF EXISTS `topic_throttled_metrics`; +CREATE TABLE `topic_throttled_metrics` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'topic name', + `app_id` varchar(64) NOT NULL DEFAULT '' COMMENT 'app', + `produce_throttled` tinyint(8) NOT NULL DEFAULT '0' COMMENT '是否是生产耗时', + `fetch_throttled` tinyint(8) NOT NULL DEFAULT '0' COMMENT '是否是消费耗时', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_cluster_id_topic_name_app_id` (`cluster_id`,`topic_name`,`app_id`), + KEY `idx_gmt_create` (`gmt_create`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='topic限流信息'; + +-- +-- Table structure for table `work_order` +-- + +-- DROP TABLE IF EXISTS `work_order`; +CREATE TABLE `work_order` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `type` int(16) NOT NULL DEFAULT '-1' COMMENT '工单类型', + `title` varchar(512) NOT NULL DEFAULT '' COMMENT '工单标题', + `applicant` varchar(64) NOT NULL DEFAULT '' COMMENT '申请人', + `description` text COMMENT '备注信息', + `approver` varchar(64) NOT NULL DEFAULT '' COMMENT '审批人', + `gmt_handle` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '审批时间', + `opinion` varchar(256) NOT NULL DEFAULT '' COMMENT '审批信息', + `extensions` text COMMENT '扩展信息', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '工单状态, 0:待审批, 1:通过, 2:拒绝, 3:取消', + `gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='工单表'; \ No newline at end of file diff --git a/docs/install_cn_guide.md b/docs/install_cn_guide.md new file mode 100644 index 00000000..311b92ab --- /dev/null +++ b/docs/install_cn_guide.md @@ -0,0 +1,58 @@ + +--- + +![kafka-manager-logo](./assets/images/common/logo_name.png) + +**一站式`Apache Kafka`集群指标监控与运维管控平台** + +--- + +# 安装手册 + + +## 环境依赖 + +- `Maven 3.2+`(后端打包依赖) +- `node 10+`(前端打包依赖) +- `Java 8+`(运行环境需要) +- `MySQL`(数据存储) + +--- + +## 环境初始化 + +执行[create_mysql_table.sql](./create_mysql_table.sql)中的SQL命令,从而创建所需的MySQL库及表,默认创建的库名是`kafka_manager`。 + +``` +# 示例: +mysql -uXXXX -pXXX -h XXX.XXX.XXX.XXX -PXXXX < ./create_mysql_table.sql +``` + +--- + +## 打包 + +```bash + +# 一次性打包 +cd .. +mvn install + +``` + +--- + +## 启动 + +``` +# application.yml 是配置文件 + +cp web/src/main/resources/application.yml web/target/ +cd web/target/ +nohup java -jar kafka-manager-web-2.0.0-SNAPSHOT.jar --spring.config.location=./application.yml > /dev/null 2>&1 & +``` + +## 使用 + +本地启动的话,访问`http://localhost:8080`,输入帐号及密码进行登录。更多参考:[kafka-manager使用手册](./user_cn_guide.md) + diff --git a/docs/manual_kafka_op/add_cluster.md b/docs/manual_kafka_op/add_cluster.md new file mode 100644 index 00000000..ded5ef93 --- /dev/null +++ b/docs/manual_kafka_op/add_cluster.md @@ -0,0 +1,39 @@ + +--- + +![kafka-manager-logo](../assets/images/common/logo_name.png) + +**一站式`Apache Kafka`集群指标监控与运维管控平台** + +--- + +# 集群接入 + +集群的接入总共需要三个步骤,分别是: +1. 接入物理集群 +2. 创建Region +3. 创建逻辑集群 + +备注:接入集群需要2、3两步是因为普通用户的视角下,看到的都是逻辑集群,如果没有2、3两步,那么普通用户看不到任何信息。 + + +## 1、接入物理集群 + +![op_add_cluster](./imgs/op_add_cluster.jpg) + +如上图所示,填写集群信息,然后点击确定,即可完成集群的接入。因为考虑到分布式部署,添加集群之后,需要稍等**`1分钟`**才可以在界面上看到集群的详细信息。 + +## 2、创建Region + +![op_add_region](./imgs/op_add_region.jpg) + +如上图所示,填写Region信息,然后点击确定,即可完成Region的创建。 + +备注:Region即为Broker的集合,可以按照业务需要,将Broker归类,从而创建相应的Region。 + +## 3、创建逻辑集群 + +![op_add_logical_cluster](./imgs/op_add_logical_cluster.jpg) + + +如上图所示,填写逻辑集群信息,然后点击确定,即可完成逻辑集群的创建。 \ No newline at end of file diff --git a/docs/manual_kafka_op/imgs/op_add_cluster.jpg b/docs/manual_kafka_op/imgs/op_add_cluster.jpg new file mode 100644 index 0000000000000000000000000000000000000000..98d239ae359dc67dfab58b532996e5568a9ac55d GIT binary patch literal 267141 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
    X})-~ibNK=SJMW;ue_8O~BK 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�!tZEZA)ilBfXy((2YO0Tg}r8lV&0TB=okY1uv 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 ZGvUq1RALa29`#Qni~py^@|eC){tw+OQeyxB literal 0 HcmV?d00001 diff --git a/docs/manual_kafka_op/imgs/op_add_logical_cluster.jpg b/docs/manual_kafka_op/imgs/op_add_logical_cluster.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8650fa942e13a099f8af2949b2823b09803dee21 GIT binary patch literal 245285 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
    Rc!atTg*89#r8! zKPX~PGQHixQ-4vNx)x-(nDcQ`Rqk;WdBG!$H46q-|bYu$$uWgJf~OMj#f+y@nC9dilUX z!}R2RC8{BR|ES5FNvd<8fOXJ7DpzaF$XN6}V~G{RWN4Q}sqsaFzLj`!_x4CeiH256 zTrD^n8AMttl50W!C1YKU{XGZyApM=g0&XV#~VegwJ%gfEhz&U6U#C<|!+>aEs>*vbN zYdXZeK3hJ+%GtVV=H)RYqpHM9aLau7R|36~YivG^s=8{=!oc)$rL^egG;CafV91#+ zVMsvBa8j}+%JS2E6_tCqrV?}$YewYwN3<8-8%%gR-&Zn^#M#(mPt#<-P=6<~>HfON z9Ige&@$aa+exVkPqvfRbuV2TUPkf;`vCR#2E}m2Ncbw0EX&o3yd#=;Wx4Ky~JyUc) zqt#dLR?gQQ^5xj{4kPaitbE<_q!29MYwvwz2o{)t- ze435seus9_Fryn0vAWREb)kGVRpC$aDc9cN9pz!&nxpK&LtkoG*`6FZifNnFr2FHZ zR+r1FN%Z}wBxVwFyu-P>OfWz%FwN6G!cv0Nf0i>Ol$(qCG!D=&~!{Ozo{IZGh z{K*g&KPHvtboD8bc`1_*glw^@sb;D)?dXX1Ji?yX-mxHsx5$KVhr)E*t}F4EHGZa& zQElREzU`PF{WQC2?c%C#N-GrLV3hW|wKzTx>e(Q?!&xV@4b6WSTN3Qc@I1Bqq^-(l ztSOGF7#l}?SOONtqx~?17J-o)TSdo5ytBjRGt<9$V*qdyR30M#Ji-uDIsnd{>zjqT z8#qc!cg^XmGt#xkW6wwXB1Lbv5pUDcrDVI%hoF-}#{X?T@#p+Pzoof);z^kZ-443w z^p~cJ`t1)9o&vpjGhOa|AwvcAv`<9?}{R+5LXM)$Gs6t0OUC-sN0J1xbxr%O? zVqJ$2zbKt3^vrFx+LOm4_jf-0?*#s62}K^<`y6#H(Q+BxL0|o)78d%2qu680LlOC}FGc+J zCjCP%1e~@K3R?x&K7OBm&YRY{w0zE#2X`hf)+jQWhhG8VZpJ6i%Z=n3A9^1e+jahQ zw)!P`;!Jcg%^BZ>;jr3FxMp0#VMQqC1L^NCUl5mz`TXkWLbxE?Skm(L}rFJNE1excoz4hiCP`?SZ1o$k=-p8G!d zUR^$VTFNEO@!0B+*=ZsyfjYb>DV%FeI0iqBZ&s94ed>K;9g(C_lR{&wf{n;mq_fwK94QkDP$SAB%=XE%6o36_( zUP46ns*kULr)E(x&ct4>LUKR8mu%x6`H2y4MO1FjUFPlvNb4&qP-yvZxH{iB&zV%a zUcHy*dgkjKVpC4)7y6Uqf@pufo;gt~-RfO7B&VocWNGKZIrn*0#sjvNQM1`oD^vaS z=iW@j^JOI;%?10#zS1VHeoV?G&H5I^!an{|DX51=N~XU2Z9e;bm+}gytkt8|4bP3e z_L=Z^dz}3U|M`*98qR7)ZUjM7=GW$#x~X`lh)%uidPh#%T#+-^ zzFwxd_t?i1uUskBj zhhHg6IOWl}1^bf0h zNE4rkc}p15TI4WotoXboqp*Xyx>}yzzL`Sr5uv}FZvU=R?v!-siaO!`&c#gh$sS&w z+vA)A>H_qO5`NaB4r{0Xp1B06H|If7AoI7H-(d!>KYQ z%}2i@``-KZ1DjWU*m!l1NP0P*&g(A7QU$S%Uf!HxWUockBQOgt^xHBg?8wF=cbawYhm$VcD!9NF+evp&AlzxCtQbaMBr6#7DE+6d@ucX2 zv55o$J+_jS4|JoCdNyK1eq`xq^A*s07{$noOtma>2=HlieuoVBHq`JkV-Y`3a3z_% znB)T+CNrgk3RV$@q!xhjuxX7yirY!V}%jE}}e%ps^ zcLp+K?$+!Fpkdv)iN|Cz(-~Uxbz>tZWmUmJ`Xyz~p%itQ+n3Ys;C>4n)Pmd*Haz{8 zZzDL7waO#eS+2Z&4U$@WttDrz%E>JD`I{{D72wU-JahI20lrpQnDF^{O4+`B*z1~Y zk2pqm|GC9*J{xZ zSi>> zU)&>=2;6$JC_Ss^&bV%HuDVe<19*Lf+PQLel}BltW#I(rzGv@aqyD-NX=jK%91bq2 zOipII-9-ZQ4w2aBe0-2U9k7ql z{b&5f!IdmW;c&H;%RJw&cH1a%xJ7iCdfL>|SSY@{wMPRO%eAD)JBqEQT8UoPAu!X;bhI9GBbQKUPPnu#a|nVxiE zsxNJQ9CmX!67wWx8K5bX1e$KNsU{1xV@sL1kaT!J7g$y&2 zj+1F1Q(;_mhs1#57;RFVGOs@ltsp~XuFEEF-`avz!aQ`AqYGlXFBQVqWRU6P}^U{0Oit1eky+A)5!2d3oOk`*-w zhUWsA>#a72q}?maPeTL|55An|t2NbSbGSDr&)q1=na@HC`*K!T4ND~ObEecJah%RH z{ydOXycWeeABaEI%x5%q+8A2BT|4SX96F-rZ=eTGe_tk9WG&-*g+^MCu1{WuBDT6I zk9U223Fr-csbI6893cyLyxr=hwB-RHVBNCiRx_Nhtu@-1C=Nx4jO0;PZM0&{w{-QX zm3pkx_-Z9te=<3%LVreL8=#a^Ijk;adXUByeE$MZ)ea_{rWc=^9rQMuGi9!_01@@< z-Lzq6@}7@si2z_s_qw~CGmqq8F=h5~3+=CpjYdW;_=5`*+pWQjJXWk9IZte`M;P4A z>sKtkS#&NjOrDfe?=^Ivg4+YmyrgIT(4v<=XqMU{@2=Yw^Q6qg!NR_r+K_AC`S*zI zU!$}C7B`t_A%1idh%RlOt*vhIldAD2gj9zBqj0v8uLuYkLbT?m6(m?jAlCKn}3*&_MCXS(B9yIGOo zc0NB2xk(-VH}q^TX)ormKpBeT!|2e}TS(n1cvE1jwL{48;sN=uE!;*uMnNUNJfgrdu`cu5 z&7-GZiBxLG%Dkyh{f#AfS!fbw@q@cQ%d>#yfg_H(M{Wk~&B2`!E?wz1weT&hcd9f1r6$65J=a zyCxO3auHrw;l&iwBH_%zM}~YSb9-L%*tRxMC2hkSt3HmO_+EUf15H>PI^seBL8mgs zEn-26oH5SQLUmPCSBrizTCV==FGwo?jFUmW-`weSdRq?5ROzZyIo|G!fDK2S8jS4` zwZ|tYAG(i>BH*xNyxhxx0lTj&z$(ncqJ$gjp|L8VHE_y zjdXeNhQ<2|5L@q^BgjqdHBWZg`##>p!9#g8(-k246edOBszy7RtW2J7;Q)Vpck6b< zMeJ!V)~w%;&Q^lQl{qBAu$znz*cW@?0~5(&_wl@<*FCpyLf^oZV^Lhlbe%~9r2W|J zcJ1-Q#d8NYcH3tJUnw_j+WUI;17nY;5sBRtNCzhb5sI`<%(Q{?n`}Fwp%+TScPl&i zu<`q$$uhR9wA);3EK7=dHKneTVQDaP#*1zV?fM(0LA!(i=X8_oPjz_B8+gOq+!fIA zW4eVkL8WWPWA1*^OS^u$+2{Rn&*{BkVY1m1B7F4r%Ot{~1WqA0UYJx)mX_H*N=ur5 zWq+sl_K>E9w)vU`ub-Ma{P2=ThVo~73vKh*r+3wjCh2w6Y3RHIq8{gr&3n6&|LtBk zoG+e*!kH%mWlPFCBb9l&;3J!$6gZZ0!= zXjvV^;b+ghMD7{D7e^wuB0CL6T?+XqSu4ht<~-12RY}Rhfc1nm)@C4>u$5HWdY{C( zN!BO>xFz^-p}3hreq==Z*jM`a zaz88Fwl@v*@a z^$~QY^QDp1p}ZsN6$|b+pFc>^prT&i!ip;&)mst;XDQ{#1|Fg|Z0Cv2r!EKUb%F{6 zlW{@}bzI@QN~$z-nmYVKx+^*FedVG~q-cV;&qjNlQYUA-^!tXfdq;&W_ zhQbc%k>O_dw$Dn6enrx$%a^7Oevfob#dGc?_BZ$MH66wHP6Z2%kBo7JwUYL}?=AYe z)l=ifGq6i)szi-#r96n9(H^41etCLsqEL@{=qFE$u{j|tf?BJ4H-y;6KN9goW~ zk*%=u7&6_~W?E?jTE(fUH@&aY(LC83?7RXq(&?gqE>?DX%aT`tA#oInX4YuXC4Gr4 z!p*C(Zh_8gD8xap#_gF^%8t1uJaen(Xbzb8qwcmy7f3z@;pm>;*!-8{!^u<5nlbPtdaf+O``XY3W%}_ zH}Zqh&r~6q)JL(pO~AJwwx7oj#fcP+Hylncj2;=hYDgMfw_`kkoScGhbBzBcGkUwj zWOU?W({jiSE%wi=GI+oF#4kC1{miiFo-ozr=hS0pEEkEo;dIfwHY^0*eFm~gq{k*$AdYSSNrthG-Gl(J&u zL7J;G$p^!Gl*Xy~gVEEBMs{%mZPpTf^tE>+I2ucJ%sA-8(oOtWtIUncaHD&qk}tKe zhEW8_#v)?}M&U``YO<0Aqg}%pgS79r7N&1&DQ~14^ zIR;=-X;8gdfra_c=lMxcUSGmzTMpk%4?B4@J0(+)Gk4V)PG28XtKVN2Cb{*rRAZS} zK;U-%5Z4i}`|?xs+!a28UDCy6zuq1aWeij?u8D#*U4YSS(c-f+?nR5`iKIJtMVCql z7KCWx>Iex^`^3GJ=9v)PtP9owtDx8*u}m0!()7n58$|VT)QKEYxk=C_t1Gkan=?g4 zRZ4+X20L!p=Z_;_^Y6-K!~ z2`7^59L-x8eX6B0D8(~V3X4kgId0zAt3}2K7+&&XfGc!-T~`2-NAA+hLzaJ{MbNKh zMzgwZRQRWR(XxEddsi_RdmI)GWrdvTnNXJ?C$NAOxKY)%295@!SgtS`4V6n)?@!$U zb2Mu1Znl{ezR#5yQr|s>JQl1Q(cQD)QTP;ef3iuYSViQkIbOVyO(r^OpaCZI86j-H zq}3+JZSv~kvX|+enHtZJXV&$|H~H_PITI9|oi@#(UnYCzt?05gclnhh5t-*lbK~=h znS({h?drtJo~ouZh30CJ<5VE@8|xg_a_V^uJ8;3I8nRQha4H$WukilI9av zc|*VlI>3h2cUDe5#(Q`W#4SzpaWL?`L*oG{;@vneXU?g0M!{0T7>tbto>zFvoO2mK z)LGiXh`=a{YPwatEEjb^Yap6_VT!1FqM!Y$el{YFsrQ72BTV+?yZ`z$3xr6)LKa+4 z@4Fj%v3&&$&5YW;Ezjk>0@hFj~tI6}yloMQA)eF@QroRFfjz=yK7Z1RQf>dxl z_JoAg>b;ve#m{%m=w9Wci5nAx(nfsomr`ZzFdiB@lQEm4m4*pzs*xy8G<)oJtCV9d zris)!giK;0FE6tzw)sQjJH+QDzIc7z$33|Gz~j2ZXjx`t$|^^SX;s#P6s4c)O}EGt zZ`IEWeWd^VsJ@?bN3Z1;(p&fqmmwm{ugI+GA(ea?EEdh|&+c9`D9=X3jSb8Q(()9^+VZ9}`4z~l5{4V~T2 ztnERvBNUS{bu8QkVGk*Ehc!(N-#eK@C(D|k-Yd;Q7L9_7HpXY?EfWGU^Mb6zRLo_1 zUa&BM7J9!(b)~tjE_3Ed=?_h6p?qiRRYO#ih@cOwy2B4|J;pM}-W$nQL|7;^OiMdc z7L||KkPkhn8pGGU|MFZ#YdD^kA0wAwMmlhk7AsQP2=;99l#9ob@A25=_62+A-L%mj z`T|4UuB5Yj_+Q=(nK1Z~x8jraGE!9_M4zrS-8rb^j;MLN_BFJ7%s!N8 z?Wd%l8_(iGI;M(cLsFzwEry$!O271X&SGksuSlHWHKA1k+^;8tmU-Xnx@U5N4o{Pr zP9LJKfWes}5nUK>dhzxT6fa^Vntf6u(XkQ=V*SHNT} zgdI6#pN8T_a2uNj1T6(U9>%CQyQ>!63Bk8N*O_k{u}J5r@QT-5ON>fLDRShWHIs{e zpQfLA_+2o|fgz|Jy~X0zk>vN1LP1rc{;>lduP~&G71I z_IH_*vI!J3@)a6!yp2$R z56!LXaBL<^MZd-V)-%qwju=+-D{W0|VcwM^<1MIxe_iV>c*sV!QyfTqFVp9k)K224 z|5h6{n_=Nz4gtdE>*-RF>sny5=-3MtmWM3XF~BfXOq{W>iD|X@`BJIP2fqr7Xp7k& z#@&Ny1ZSb54_DY({h=@QPTK%{Ev(wm4qpTwD&}+sg=J!>u*O7X;b+n&Cd(HH@P1#7 zRH{xwt@ZVNdY;bweL+bXi(<>&{^HdU8~>$|1KZ2z`r7ttWNiSnUt~AaJk=LmRt~fv zURHx~BnEvtx|_9lr%#?1uF?yw&m-iO30xEY@+oGuS;#3&`NGLd4o=$v|8dF3L&(*~ z>oq8&>cVTCBjg^k4=;G#B_ErtA81GiQ%CFU5u*xWu7n3=8mk|FEp|$;{C4*>^#adY zx;r&}@YtSt=*ou{93y+NWaPo7!zou_ly*$n-LH(AX=gh$1_Bj7f?fu^#Lgqi7hb0K zgAvheqbLxz@ebAv4W`l_CJVv^!EeOq!}C1cZY|xOY;p)h;7)WfQcuCg9|sE@nyuHE z#1ExlBf|9(sC~a1w9w3xS6NrXJME37B?2iMUl01B90n^{UG3Y~!q3loH57U!T~a?@ zntiUBI(0a)SBhc9DLrWE+j!mv!TW(u>i#`v5|SRgmdLn`qDD9_>?WD+25{s%I1u#J z+%u~rUw9Cd2s=>srbWF$ILVJzGk9py%-?SauA0G+tF$ufVB?EB6dxAIHjLl(IcxBZ zkPgLsL?ps4!lQ8>}pk*{r7g~2hW^Sbb(L4%1)Irk4nOLHB? zMfX0A`;#$iy;p75DuBizMjp&$o9{46BO=3ENUGsJS*u@(T*l6J?(N4)3cI(*CrE~C zcn;g6frrtWJQ125nWhartwr`VX=A=l^&Y(yAD<5j>|+GTg?WSfl~J89cTqPd4DUD8 zJ?=+KR*8OE{aWmHZw}ED!{HWkWMG-5Yaw#0BeP1Dhw?sL9=IeJgt>C5s~V?ey;3Gk;@hk!X!TXQZ!dgr6=@3Yu`K2~Tv{ z-a=!s6JTbh!Ni2R1%mNgkgp|-fZ1h_ejJe&;NOVsF!rg61ql|R^9BaEKSbdndY?&it)9zOR5iQm#hECAOCyqGZJTcxK{uH3?ciz(67)HdxR;<8nxWu zf1{z6lzL5|=wRR$#7NVW-aQs}$>NV-?PS7uhwypv$+)|4E~Y@uu$qWd3_t!jWif^| zA=}Vl0KYd@ov81(M>++DdGZ|BYSqn=DKGAUnkd_DGyjyf&6r=Ud zehH;$J+mhBcS`9wdt|cf)Qq$&K^7kBA(WzE@mh{Y_A}ZF^c~pWk7&f0k_Gm5)!jk~ zMC4xZBZ(AWD2xg3y}$^=wocnfRx;~N(-Ie%4q~rCkOv&bl}oEzozayv&YC`3c>F{; z9NegM`#}zw_sj3`F;>cjVOM=iHnUQkSa0E%tk*&lVtLGu&E^5Mqv&;PVVDYXS_P{s z=*}o39TBCxv$H3Cu3+bl2eISroJ&?T3+~xTd;KCk9i1klAv}I#N|vn&o5PEZ!Um#W z88^-zdzycP|3uy6BM6-p1W)AMdk+|=bW3{I#&BP<`!~oaoqap7Y8!gMD(-D4K1f*C ztDzzOi6|x%o;i>7+ik&UI6AC4JI-0?O6HkV8&p2N^=Nk8nK?&U2OEZBcbpD*-aOs- zmaF9p{OE`-LutV!RuR*_)7Kz6dHG{q*t{fI z;}Pl&p|3$;X8OcnetXQh8ENx#ds(BmuKiFsp~{ROH}YBB99$BE4rBp0%se z+0lR=DI-XQju$g|ECiiIgIuOpT0)=J6+e`>i(@N_xQ&UGymgx-$i ziAbqS7H5#>9NqqxvukT1H?DwwS%loL@Wap(g&7-D*Di~5&Lz$(;Ir8wDmnl-{*I@N zaPEED#L4+gS2dn6-O*NTR61e!@dFBhB;;oOA<@#MHiEFIbjN258NfMufYB6pR%tm~ zwqHh9G+o2J+%~fWz!TD8i6mw5!jd-GA7ete*KO?etmE5KSJrBrIxG`A0s@gO7rk9X zT;GN(878XWC|Z{ z&EKB0NvmEn$=ddIR$7|vm3CLAMf0V380YpHYht>YQyb2gz+JVMwT}4p^YsmX;E1Jt zu3%04Ft%?@SR#ba@9CuzY*FMbd|&j?_5HVn;GKI5GK1ytG>b+gafnurndFuUoEzMk zA*e3Q(wg9Xa$r5qcR$@GLA*cEKbpac$vcs{?EnBy_?|bEy)C_z8xt`z@bvWc#BpGI zVv_(9bbmV6cyUY=!E~h7Bm>5-Ti{_L$CHcSOXUd7=$4xZi!hO2Qr$dK=6*^#pDj$V zUp7~Yq1kwAtux(K8DZ)Y*iWl9n3*0k|JGM2FUg(MkX^!sA5Qd^0`q<0>>h1!PkQm) zTFP3Lv3@!)8_RIHi(e(1JX}3wm)P}_O%$+7o~0Ce4>S9TFx4b5c24vNfTo;aalSPM zPFiElr6y1KJ|orISJYwg&fz9yP;Ay=T03--rxEd;^rRl-5jzbcHE-?S8_(^|L}@iA z@N;Cp>)lknymuQzOK21_QKl)f9*Wb%`jG}aE065=^@}j0OQL2vF|mqI`XGY?*wq1q zjg{X|{{2sW{`E5?0v71$`_}A^1UEVA0ntf$Hc>wd)1ur!%f}@2qzcA30SigLbk$%! zon&c-I1hpl|6cK1V)%DY>=xa8c-STRrWlqZPhUu7`IQcS&j^id#8TNXOTOtX6Wv#y z<9xtYlVKaZ`f8@k9(A*_ImYTuQ+>driPg&s5!U^WjUu(LkDD^J(yI!~a#y?>S0hL` zCbegY1(3RFTt1;P+ThuJKS=Iy-5b{q=TD2jD(Kd5YXq?Z=3>`0;is{4YP>;TmXn=! zw#<}{a$eML=(SI*Csw2j=j_hY20Y)WF2FdjcvMa?eVC#(X-3bq;u*<#5sM;}QeGuqy*=35NERDPlVMZMQ1Pg{}VMETjjAA}FRn)rWl;%z5{ zWP-3fZ&&oT+emn;_IT5HbINKG+Vp-7aHEMnHZzAs$wc@HVBHZ<`1JO`A zgwK5&A?>}|W{YL{POxA`*9y}2GfvQUT?++O$x5$OlcP&XSJ&a*!Rh3D45P7H+2pD1 z+>PMjhsZ;n`epaRokF#TsADmU(HZA=d!lnwFPkDZ_6GurPee8wT&h1H9S77&VQozx zH9D{eGFyvig1A<*N(NUe0&BQq7AV(F_DmijPRYw9%#7;IjC-gr%Tf|~#MusBJvki8 z*j!?J|Pri=DdIbBtb0nqmo%Lu~RZdsOc)s7)ouNvBj}?PS*8)#RqhS7EWUN?T zw=jQH_ej+Pt0YD3rc;4{BM2Csm3d*A0^(ys8e_FR(hJfDK>ibCz%Z8ufYhtn9!I?*>d z@A{qQ*~d5Ne>~npMfB` zlq(f(hzb`e;-e3<+gS1cfQ4q?gB~jjZ%2VETQxPK-{uwVo;0#Nr4%+zd9EEM=)bdP zx)mo)w(1K08;n_V-iZnAilqv4TkG3co!Zl% zm!4*h|z!`$=rw0@D3T3-b( z&x!-TrqY#L3aL<+wYcNVixg#~-AX)O#{`m9a{@A2rbbnjW8`9WelC9eW*{zZRRvN{ ze{62${F5t)yrz|Ed3OB%M_+8~`iys2JB@6Cq>2#F4Y`Phs7P;%xg2me19LWBPT{2) zo=Pe%Uphkx2fQe$sW`N!+3;)$JUL+1DR+7JOe3^DR+U}7-ZxrJHnN*pec zpR9i`#_A~i6H8MbT2MaD#Ux4$32y60pVica2u-wBSyuWavmd{Ya^i27h#Ae1@w{U? zQ3pzuwYY%0{-UtR&aKRCm%|OxgXhNbR(Ia8Q0jMfxcz0`Wy3c{G|oi=Al49Fchhh> zS^V@pXJ}T?7RvO>kn_OGMQEmI%``DwmflZjwfp_o#0apS_D_ z#w#^pUh?ekJa}&(5wS}2Xb7a}B0E<@!=?T6=eBchPqZv!yhOwDXFFbNgWhmnvgCyN zJUr+z;RvfgZjG0g`N{7GZT~@)))12M!CV^S$=d`gUzx6Ji$F?X{PUqG5>lF~`2HhA7Gz zgAn|Q*2=d{-pTsM@3TB_wn?NeB*+NdF+Jc~m79-3$uolIG0J{~Uf_HGuyM-~2b)%6 z4Dp=&n!4CeB`HduXZ{lkpZfsUQ;m#aEYneJMDCnPn{tmFc8Y#wqEG&6m&t52lfW}( zvhoSLkyCjKF+WzL=}-rz*c_4wi|Cp+t5Vb(jRXS&@R#Na^FsY!R8ZSz<>QskF4H|< zUkYPLSH$<-ihH#6q1$Z<>;Gc!yQ7+FyL^MFNE4A>qXL4`qzTdjB2C1A(h(vEQbJcG z)KH{I6%bI6CQYPwsi8MPs`M5@lbTQigm8~@znOX8_kQ2Zy6euGSu@wa;GC1w_OqY8 z&$IV$|2E!u4idD4t7FO%`Z#(li&^@1!;JG)c=x6PTNLRT-|B72jTfgN9va}2{J8fN zlz}OLPI9%fmWv{cn^jgdsA+WEx$C0k*VbQZv9U)pn@@UNR%}=37$yqgVRMcgtI|Gs z^YvmIqeigXeao6m3Gvi}l3MN{LgPqkxGe3jnM|gHb4W=H%-&dKyV*JSR8;zH_n4gG z&yM?NmcKLkTsnE@MUK|aH&M=By`{>y@XSSMQ^?@r8NL_Q?~gzk4IoS}#C)6)Mu!;D zeQivp@rstjk6HBoE5D7wh6wEF`Y0CJe3WU_79Z{)^zowLHm6gcxjyy0zif%%s4P{5B`jSg!ZW4N+-DE~*mOD|UvxK-UASkjo z0z0|su`4{uOH}6u@6%TS`r$HKgD^%%`4O1%ZH*3sUe1=xt}avzr@S0=4}4#JXz@z- z@C}3y9A}OA)<|T;`(+9R&L0a`jpgUvit33Gp1E>`V?b1rB#Nbt#2XqTFN8>dVVBp- z=F0oCVy0|gd01xklzgNmHH_zv?wrv%qiPqq=ZPNuWxtXh;N7$F!B4&pxsuOJ+;P|x zDy+Ko;jLK5q9fb=SYJOkZzwEp5$hJji_P~TuO7mrDuvF-=vF3(@&#RCU=q-{oUX#0 zJkIjny@;dqB#uZi4lBS8SbV%XRig1ito6d)quE>g=BfpN0Za8AJvyIz{J>-uuh(fa zAzM7nrgnFI@u3z&{7F`!taG8U+6)KoX4i-LyOVlO+0Z=hFDwbU zN^eCKic0evm=R15aRK=Kmiq=09dFFUGGhX1GvSv%haumkUAq~6<>#8IAnwKdV$^Fd z*JpF7Z#dbi>afqh@xfHc-O$ax#2K&3p(KS{T z6v2(^^GC2sj#SkV7AiFS@wyXS4=SZ`o$YGdsPWkrea>4a$plw)-YwQ8;u88Ql@nF- z3}ZOm7$a%onwJ@lY2OtK@pmo5uFBonOMdj-(?IzhxW2bJ?wgwa&9LM)b(VI}Pt$;7 zKD??nHm5lx^M~0jX#TXi*XOBQZw9!cxGEPlTgE~`hdKKm0}bcajFf>4G4I&K1U{yD zNik`BW~_^e)cV_}Efp$?y>=Q|OfD{%Al9CMq2_PmB*n^Ag}VwWw>sEYkjL;DhET}1 z?I^KZrZQhR5B2g^$2j_dDeI6vM^z!>mc;(IW`$Rx=c4Op%_usi{p9kXjVLlA2SF-& zQ_c5Ge%XCPu*7A7@2fPkY$)Nam>mvVL$@;JL zl7H9_cyQ!`_9$en9ax4aOT2ukMfQQf2GnMmp=Xcw!AErZSAnE6-VG-Y<*;??oB@vt zULIMR7Z=_)oacI`#>D#!bY5X?cX?*z3T=P_Skg-Y_dE_~1VFBRNaHFbhphsOgt$~L zO-!nwzscMpy+aCeU2tvW$Jpz^XuRzDUHR-&mL?|E5;iC=O|6|jpjxdrwxUw#YLr@P z2oGg`3KhCABC!?-q5|p#flB|tJ$O_Yt5sOWJ!#j%B*C&ubZw8-bCB?(TOR#nsf2rY zzjXY8LTsbYnfGg~g_Vy4?nRYe2*{I-DFayRL{|BgI`q`D5iRIfNi0+G33T^pK1cEm zBX1tO3*{S66xS7UX$6tX=Zs{g(VW4Zo5Q=}9yzkE(W3Ux*IRLvkMf1D**nvccr~WI z&CdW~a`y||iF~T_CZ6|!^iGQn-D9g{m{#@n$0kSX>ggShj2=hyT4&RmX}7`^e^F{x zs!PT>3689-4WVbEIpbd%OR>DyuvVi<1X9CW{pE3iW?bA^M&~!z z&6h!e+)gqdv3Ck7*5;5chOH{2_Zfje&;8QIbugbB$&LfF9KOgXjV9FxY&}c2?zop1 zUs5qBegfC79j2K`?X7{yAz!6)@thw4RboC`m{&W7B|=*#9nV39LnPMtzlq2di?mrk zGjG?OaC49)_4kJVw0FEWNKnmsVqMb%u`aD4v50zceeQzU&Q+>Ar0GRsz<85klZd{s zLovYVby$;H-5vDdowO~6&Qp7I??6pv?6i%Tr%N-1*qqzh$go9fMK_A^T-cTe4OPSW zFJU*A2Ja>E9xFFZ;NEsSSzMWmd~IHD^lz2}%D(7u!3QhXeEqSA_j5!~OYFZd$SMwU zW7cBk7YlwHL*DpgC-TSq(e!fL#Q?d z$;_QA&Z(b~=nL2+L=cogJ*(w4m3g;lw#TSMXm02y< zC2{U{OrlN6>7^I-Q&h=jeC53>f%N~lZK<`q1g_PG9W~_@pZdVBz=2LyT>snvw5C{( zL&UVC&}Qa#QX~A6&BQy8%Dm6FsuHxeN6u-uj|Im)d!%@Sr4h7qP=hns%+37iF`e}D zs4Y{!a?pEaNnzC+tGMt=;$m>RjXc}XwSjUO%knbc61Cx&^ZNqs+$riny&k5Qw}p7I z7;E*WZ8XHHVtChPkI!z7IB=_kakB2?U1p0InTwhptw(OHo?E0wtE{jP!HwPJfwbpA z#*Vl3PC+U#F;T|v1`ErT@LFI
    23@Pa98`VC*tmr-_Va&?+;v&gOikZqPgl>x9?L}s(FIKy zgSv?{Nfscp#zw_lA*MWnQ6|2WgL2aWt_OG-WP93-nTlI>50x$ z;8}ylP_8gn}^mFqhXdoMYW)k6+>PJohV(pzlu)gDm6%-gomzwn%F zv6JE0P=bXr=+%@F7r6?gz_{pU)O;V)TSxC-TM!=4oJ7JZ$=ZPIHzkHF;_6<&!$>}U z(cW1uB!x12qDYc&mD-}Vwf0we?Tkz)&b6Rd)W%*OQsl9c#!RP9{`KAc!$oKD1TVf| zN$CbL&=@@)kJ@yz26lfQBMSyvWfhtYL*HEYh4%mUeu% zEZ}>=gJIe3LnWdvl*<%nh?% zwG5W!1oKGqa)adQygsSq)iDbqwK+cvg)UT(#DJivo9BZwYp#Bs=O8Bxl)T?Xw45)Uhr`FEupDw>S8|}5@c?Bh-i{8%7SuV<8mw2K z_v&Q-I7{Fu;uH}uO*EFlHL0r+bl_q>EoX&^20d!%4-8Y}H)W=45ZS#q1Z{Afes=uO zA{afr-xY+{VWAczX0NRA1?a@J{#kqV+J1E0Q4Tc|R0e$l-#@M z0YEg>yn3tZ-+70AtwR3)_4)nM>^DtPQ8)#PRQlmB09EwgVG{(ujr;*2!FHue1Ar|p zfZ}fULvs!Ds+^b$wrQNzXoOt&^X!oIDWBQoQd+I=1MIHz95d~<#96zRwQ^<705wSr zZ)sOetY~Y^BUd(^{+p|)S5dv=$7RauHH}r3Z`lnnXCBu+t@-}Yd|Hs_Vz(%ZVR`jD z-RX7VotVVzw}OmunsUZCK*i&xT&K&~zRzzsK`rMD>&HWy78BMH+hYT4-K1??bHRRq zWKow_3mVY~fU{))O0AYhUts_)*Z?E)wy(GszIyF8cNm_x@c57WxN{KDfvSky&vV%2 zEx&`P<3QUrta|pVHgRXS-FkdVF zWD2JrO8xL+4upG}Nh^edSc&coVkHmny>#C|FZ+4O1EhbK5QVR)dNlP+`uQ@lEAyq5 zVn>YbZ)9+fnWk*Rz4pn5kt9-#FtQF8wr?R;lqy{}!MDi>sJrZ>P3FNw^`5uS@pMo88-U%(*49zW!IaV z*pqT^Bdbh{fB=QNEIvM@%?go<~ln*hvsbN-W9IX}unA*Q3hW9*2{# zWx>K?V17=PH*U*`VPCgK*laVgDDnAs`g1{#cbj4snz;6Yww^!1 z6WyIakf>!?OiY|5RD(DtQM1@t;#3;v_cm%T+mK)}Azq{00NvT0-nNjKR!3^s%o$w` zoC`?>hIca>EXA3FS7Ru9z_#hU1bWB?o=%^s3iHJ|quII5QO9Ss$tpK9&<*cTcg=y_ z)%w@W#D4+Aph4@Go*mt!p*8SOkxGZ|e}cs9Z(UQ@q)aM(!45YTkdD?j$A7j{>GywT+i0EKEShxtUB z{;zlc{@M7l2NqsA|GK!fp&4pqEoozgUvbOB8H9dFI`4KtKy$u zjdsF@`vP~8ewqAVC!`QSYW@?)di5z`ZxcHTom@FRJJk6du{A2da?A#-<9xAQR ztYnIMIJie87Jtt|8Gn}Zoihz-HJ_)i(E?oXAKq?}|61(-vU&e~Hct%I!9s-yRgbJ5 z@KSkKA#3=9hqir@483JX6XczSYoqUM$xI&!$}USm?=GOYro8S8+|^BD_!McvEbg>z z_NY*cS_x+vclHnaclcM+{RemUyOzm+*y|10U-6tj3V*fB9xcD@us`}H&u7}dSYXMe zUySY_Jy1P2*Dr=PWB;!?n%|kg|HG|*^Z6?tr93L?7w2g!{Z~DQfuiECKC~`chddxV5mL)u6>7gcU+;zoO`WYY0 z9sT~?idFbmW9`2dga2=T{XZSiM}Ik@?_S(R9-|NDzgx@^El3@`G>j9@uw(->#eJ@e z;=-GHT7ix^@RV-MQU)N6qen2v1uGCQ-P^c4S-J>nOpoFvCh zP@|rlkmTJr3z8_1s6&u+IHShHqx}fu!K$v$ZEnu_x^E_Caw*zj?y`Eg4t(14)gHt|nAiQQ-5k9xV*X<8sfRo>yglo-M&Wj*U=8}D!3P=5$YVlV z1vw+T2vDg?)mSukx}N+{8hTo8(Pl1y{TPUJA$K@Q*Z<%qR_6UYYSu}sCnTRMRKYo1 z$V@!ZsFf)z&u_ZD0Y*Qx!V|qjZDA(*El;F!CK?fAYGOiOL(ZkBwXxM#wZ#N|uu1U?%2{2QpWTTQwT;a?^!X+(664X}x&dau*%h5>e0n7|oj(~L zVWRnVHZaoDWX>u?&^grg@feVpHOZVmfK*`3{7b)cM(ziw%6>{W6=I*tnyu=Q={L!} z({Iw}gG11_eAMHIjx|w6TgP`UQO}jthFK!4$JZht!gN$=&lh)bv>p;aHT{`jo^}r2 zWMK&bo5APi>_-RFb5D@S*8Liqb}kDm9VQ#T`9nb7T3RzA=sw1$li8w+0sJ#A*~uDT zEG1<-$8^iVY5m#@k!YgNIei`c%TL>JBri zk|@W0<_xr_c+D*_l2~@7FLcsY1xEQg9(~`VS?^!CrOY1BbX`l#YOdC0pl>4`=Xm(` zh2q4~z!E8RZ%$=8>*@H;dk06S)|&L$XZSTU_a0UDu)eA*>`&^WBPhoTmq2R$^eeoO z%sko^69Ri26Xxoj*S?o_o@twWTuoM)bQgoOA8(r)bd{M;>tKD{+_ItTM0~PlG-77l zD!YTHs_gzFiK|b-A6wJm#aMa4)v-2^ZX}L@z!RM3d~g4CET89 zR)e_G#LRdgUThIb`6d=K??q5|2Q%WWw~|Ge<{Y4nq1CFoTY7IQN=cd9I_jQLgbdkG z)Tz`zZ1a#{muzg3E~0h<%vLOxRbn4A*1?$Q#P9y#W!=-Qj^K`W;Ha~6x35h?UZ<9@)>8V3-SPm;&k@$T~agZ$a8&O`NK0RIggNh5ME^9MDS)_Gqjz z!XO^@^%4X_SfoN1hs~2zv0-HzGBsJY{F!CFi?OZt zvo2wca`r?DNTO(e7t*)nC9TPE|@#tE+$60FZkYOE-qasN_Z z`gwpia`s!dV5g8%$gKg6g{ZXo#>59aQ_XBx;ZBD2f_!X_!qkiLEQQ*}YtqpkQk1SC zM%~O0=5S3jmMPh#(7&FICm2mFQ*fk>7IDKg-GRpDACB9 znHjKlj3{w?&f=vk^u?PKddJoQlZha0$-_R{+wM5gGJ%Rc^eDB*sHDquXt-m*ZDwk> zaUYQ~1k0SGraL3Sd@DsFB!o|XmX{F@j<87}5Gjgb1^4_@ToZ!b4PSk??QFCthYl+P z0yk8CHJ|&kO}`_mG*$)%6zatdCmIjb+A8VR3_%Yt6R#{D23S?2w=ZNqwB0YZ_hUaL za;QmIGULmz;W0wG7YCuWibATHm^|U{8?9YFn{8@+=g3+4&a$_)D4HlhX|cE?``odf zxxetya&IgCH+NDlydPv_&{QO8LAjBUX30WCZn95gBcB(9UU4lXUDdniEg`WVOHZCD z_7EORE1v>^EI>4yYY>@s?Bm*3gH~*W{8rDbaUL)mK{=-y#~)8rm(l9gO!B!j3NXEu zRS=JM;lN?Jd9cPC+a^IQXcoWASz^)wP#kw17nPQYM(2h?%TTJXr%HPd)E?@)v*E3M zS5gml=feAd7LVQM1FM$&m?l9wx!)9t_El`^6e3Fg7#;b<|FsD&-S^Izx2~$xVb&;3 zI#V(dEYOUnFuj-6;q&O^EQQMCYblbSH@Wr0$4=b)yts4SdyobIU-Sv)vR$hSEzpTK zZ5;c;e;kcpr4D_O^im}o6(u&u-Vwe%RyQQHtz{8q-1!FiF~jBZqka8Fn`Nadd(!D0 z$}dz~DjS*pS_I=kJec*^kn_y@ftbPP$<=__>mq;S$t)yMsmyJybem>E_Qq#LzJN zefECBoEttoeT&sXr)MnqLAmH01W;0)fm(DKuyA7pqF;*%@}@?*j+o9XpSOmB3H3#I zd&cp=hX!x}d@J0VdHZnBlSBwP{#eCvzNe_VGVMlhvdTeKW8zo*jf`;-Cj&in`J0s{ zF|%u(5CicPni|@HTctj?&6MlyYqAZD*uspgH|S@T9(GwO2c?_AqrDjCBm_L`z|JJ- zkLtc!U&0>ug+3VV)jA;Tw!_<;;@5r>OmN4FR99mrz;!)E=T34#AN{Vfl0 z=DNhfTcLJ%YEqR=+|^#zep-0bK+3<#{%;DX;3_=OtsWj+Nca5Or*BGr zmkKwMP`e6kQh~|q_4Ni3Cpimd3Qkl54T+->ORKHDjBoOljnAUCI~M6e_lTI)+h5*? zn>?7+be#@jZ+`!(Qi0b!#GWB=!^T|#kO1AT>R7P|y<)9L$F+DBs#;R5OQ)5GO^m3$ z=6TExIvk9_{U)PIg16y<>x(@XG?I+45R3ZAkxKkgD6)6dt1R zCBK`$;pE>Cm-wdQYKJ!ownS;t&jzs9VGOG^$shvvK6i&cZY0m^8r0sqm+&kx4$9MI z{SYYt!YcF_7~en?YNF_Lm1r?@b4G10k_qKw#QcQ#+=)HB62tV@YJ+6k;piOQS|vd| z+00J`*Olk)(px-|HsHyD>YyHBhrRL?%D2QT0j74HRD;U0&XFp!;?OktI^9E@hxFU> z^dQz6o?B z1v>EqimfFF0bAN1y%WFF1D4hNAxeN8!qC!cL1)*@MR4xlk;m%-qBDw8WmJ|rSEnaA z<_s1z2MB1dRQ4lb+mo=Pms&Rj&p{yq$Cm^qn6R4ITu9btx?B1t#m_OL$ivPcS8mIB z@w*%N3311oDgZBr^2uwU8824hS;~xf{hXG^ zd{bR9@NU#SO+-&BzB1<^DGuEaP1%y=!sEhbUdVR&rnjF)&k1wU?eD!-5d~RdbcqQU zovY+=!9aES4H{-Rar_%jcqV8{G&;P#slIlJw=8yW?!6TX?-N`V&Wbd-l&d>T-4jZ)&E!){OW)^9$cx-*Qd{DP{{+iIW-*Aj^4tFWdv)VK1 z;#I~PeG1!(O!`MiNU9s`y@WkizdkCb&vKJIB%m8VR}5rColC3Uc^-4#$*r&lLV}SC9>vv+TiGuzT;Pr%g-(!%-%0J9fHf2AP3-u z^Oo04{@&#qD*-H0^%$0-yv6O)nzvYY) z<Li#E-W5nip#UkhH=x*y!=Fpwm3}CwhTEqj))GK&Zicb!&Xi7Sr%lyd-ri+9 z=Qf11Hq)l;R5Ue)B&U&|3e`Sp4sQZDFN1E6HrlT&Q7+uvJsx_5I+qowWMa(oUrr(!+zbPGn4 ziQJ?XOf+%E#V3Vq7N2?a_|?XW0`e*p<3}V9><*1d%o!mI%4EdLU34ib$jI8;#kd-s zH`s0IL~wn&Y0d96V|Iodel~qey_Z-2kTj{t#6-w6944a5lvuP7n-ely+f2T&EjJf* zCtm++(>XD6{9KkGyeVYxf%Y&!ZW-gfX`$x=_SC zX`vjBZWPVWhktI|UMZ6vtbd?*Z}f7fGMKuSxJdr;fyBuiMxdifXdJozI>BrnNXRI{ z5tGZXrQ$}xQdRnH>K970uMlR~ij^|5_A5HzRy^lwMylud+^6n+RaRLfUmY|y+q)Ic z$!i#wn~rl7$YX}BmCbV^g|C<}s&ghh9_uMQi;K|YrR-;nV6Nnu*zUTZxBfJ@jc!Wq zjE0jBA=+ou10hl^{qEk6L*hn<38GH^c5w5bl8j@&BpCrn*01oaf9ARD!DXb}x(C1k z=5sYay{HEe0swVJ;jGJ!mXr17gAyg-c_1RP3Zv4Nr&L_bFMPSL`%Gv=_nwW)!YFaf zr?;Pi4dZ6O9-5!u4u9CaxQFqRbZ%yyGn*@j@QQdM&Y-(vxVxL`7IHTW5--Ktnc`*j zQiTo2mQo45ALA&>h1kE11%${te|9qUc)&`Ho>Z{pcF^cZoc(xYs5jGgXk zJ`g9`NCG9A4t`S)+yRvZ(gMx?$M%3EE8BKGJi_^Sf%V&lAq`UR%@fG$hmM)XgcoPc zrg2|~MIkG4A&r_VWtv?EerreLd0iJ*Pe`a97|*|n<27|uyr(*=h2tGe)~_kL4-9Y^ zb0Ithwp+$dYmR%8u-*A6t`TdFd@eaBvpCuQvsB*7)dcb4hun4E{iIG|Q)3bW?N{cF zS?XU^EM57`SP9E0uO&Y6&PoXGaVkjv=^ll1&_V?D=>*wKR)c8m8O#t(gDfhIV?OfE zI`aK(IkOC6+TRosk`AUbhn9yU{5Wb+jGEUrXT6#u10l99*A}WnKHjZ9@NQ@8rIQ57 zO7=LW|1^%mIYSv@ZC!lPIxY! z(8$qu#;0R^B6Bl*I`p~WixR7n+I7Nr@Gm;pZ41l$qj1ngLBvmks5j+Eb`irIP8=)z z6i2gr#G`{_@$+c}-aSh)+yFY7teIoW4Ut)eVQ{Hb6YH&!@}x;jmT?o?q}QxRHswd* zw4sN?JzWTXqyYc&&biFTLTQ70?^C4H(&F#EPgE6c`p0zvao1WXJOwDRU3>x5`JgX9 z>eJOP3j)MMqHhJ`le5{bzsod?;eNFgbx7jh0i#=m1k&onZ5RO!E(Z$sQm+|aG-w6s z*BRYbDK)@Nkrc~ti}N@pp~79x1WkZntni6?W|0Kk_h+=)aP<55c7AEmo8RdDsSSIU z@eWuMAlST;s(oXKF^}EY(w@aPH1?%ueM#gv8^h*asxof?B!LkI=z|FY4p?J7_bKF7v24T)adrGlmm1p>Ix5>DLOiE}(kJbP( zk)tIdgbRTxdoy0;xadd0_bn$jMYkywGu7r6uG`?87%5!e@z)>jiod3c1Q9K58H;69 zVPkj8oL-onJ&xtiNt^Vj#_d+cp}=7YZ31c&=veXgMTyBPb`nh_$H#oLOjJX2GL^s~^@~4u> zrr9W*@Wn+U6*dGS_C+`~VMH+Z=fYM!ykMZK8!Z187&jBd%s!e8sppb=#Jz9(Qam$Lo*Ou;{QS~kWos7sQMM zIOm9N1_@w;1Z3$JFTm)RCYzDGL{5Zn#or~QUhnHRtT5~0WUuJkH~*-J16Aw^xv-3nm#^C?P|U^HE1qQT={+8 zIEAJjmiqCFBE1~gDUqF5Xy)ST)#qR^#0W@EMPJ>!5NkrWMDx8IIX2=9V@4(oh3eI& zOFpTfmQJ?1^(g%8-EkQiaRAp?<2}@UutDCEX>a0pMvl;RBYqPOZ4L}?c_&#aqkK=m zbTP1L&bwQX%?ZkY0td8k+#eX`+09z2+fn9s#0Y3l(Wfv3NW$}`cn1AXI5 zK)=XI*vf)|U1Md9-n;wwJc)+o$^`f*wpV7me}+{54y*pVf6VDI@$L03kqEh)HCfpm z@VOZ?)26Pb!BA;;IIfN^^mW5BAAD6&VlmK zDx+{UtLRjX3$JgkBmJrXql4;7&--%qZNw2Adsn@PV%{`nUQNF55f1r*BvTZ!(KSdI zI^OP=751TR%KMeh>#p@!JqsHZ$+uv_`|p+7{A<$Z*~oV!GGM$F}U7 zD0Z_|JB;acs+j^q`v$B`Q?$Ypp_Ejt1~1w?rN0%YJnZJ!PddX0k|IaMOA@3Xb93Ph zfHgil)MimNQkKomiKIw*N`0PJ6RZ&yaf@i%KfLXx6`+TnoQ_;Whc)WsX(15Pd>ai) zdY&}fRK8*-Wr>ADUsumWS zd&e>CnZcy1Qxp*6`7L(Ds9BB-aT2>z{He;Hfyf9j07RD8yhw|`;JTUsfXKLV2R3r( zKjV=9^(Fwu{?{b@YZCso9sVAhu=b%-+}p9hXx#i8jf40V|7GvvK8@lkBX0jUCQq{8CjOUr#@cX{ti#^ic%sxLx5du3 z+@I*C3$3&5a<9Hs{e|3Gt_nco{fV{uZP(|dbE)A!6HWi}2^{15|M8*tzg*|j^?!Z( z-zM%~bMhxL?*G|!0`UUGu>XD4LhPr2K3M~RKK;{;TD7u!hEjp=f5S=n(>TgFvh4pt z>5lvH&t$hX|3<-X(L(j#VO?+sw$(VNj{YC^-Ycld@c;G&K@n-vJE$}z^bS%)1q1{H zqy~se@4W}2B2|ijfKrtzH435k-a%@B(2~$=LJbh&$!})==j?ON#hHDx&$;+tG4BkM zcP8b1p69#P`YfQcVnVL-?foX1n-Jk0!2hEf{C_o*2Bm|ysRWs+?_M(N+wO~FLvoR z+QuE@`k`ibsdIDFO3`znSkEgJRNzmKh7K+5U4a49aXN; zW!16(J8803d5KHy2CLEu2iH+aL_MI-j98CP%T9Gg>E^5EL+@hL`VYy8t%K23czMi; zdgz9IGqj+Fnjh9N|F(S7#+W#OJoYdOm@ zR69&N*Ga!wPQ4oW7DNeV$N77J0TgjCXd(*_Y1_;*BG3wPv$iY7-cS7@D}Cx0`6{yl zZ@BD+16WVN);6lU%ARTQRChvfVfHG|u%nIPZ||D_F?hivCF@oGg(G0tbZweX5N$U( zIl5x<^HLidefA#H->G}eGu5l)@Kc6k@WJEqAhfIBT*nKp?_>wBI)C3?W3gRLH$94%6Hb&)2T#VY@9oM86(kf4j&h1})&oLSqjzbTFItf+ z(L9oH*=9XyjqBo6)0X6O(aO3X$HNbkHsAayniq{E&s8GJ1)O-GP*l3XVpWCaKO-%c z79&ke*!fdCNPP6d0)XFiTDUf8U$;!*v(%W;v`jzKrb~1Z1x$UKou3wR>=&XrSAdpR z(xb9;2`jf{%6Ai_jj-uy?t#vH-7-ejeNe9Cl!^+<)lzc$xfuf-sGXb`4h))9!$^r^ zp|R~wD>Q^*(N#63p#Dy?Olum~*l$YszNm2zg`eaa_EhkMf@n2Ay}cabT?4@A`9& zORLA-J_w)iNb=%&YDNo2})S}uMlx4BNF4HzCO!4vbKx#Fh6o+4ohShto8Oi{(;FbH;8Y#6+guaDR#gSF_HKjo6VT z88i1X{X*Z@_vhPNXAM<(cWwrEsGIWL@ENC&WE-jB6=n-*TaLf(LtVJ2Yxf!29QNh4 zoFejT9JjzAo)%X5KK3@sLNoWO=O0>TVr2h#3XR)|ae4{oXj?a;i9_`2_WKZr!+0X* zOCC$s+s@o3yp!Y!b=BYX)-AGG$_~5> zW7^HFtk0KYFA$fl<2hK*_vkOSPDtm;%p`u}uc_-f&r`D^oNXS#Dxi+jC}JfypaVju z_XAs1?^%#_P0-3kfX4wI*9{cK$h=B#HOwUFM*Eik6fvhtBx2sVpdj3#{ww$sgFX1t zBJBTQM=6cQHF?^f2i0(hvsn4vf6X{*K*0SYIat7Yw-}nTWx|+Bdo_v<6|J}Oo*m#o zog=j3e4QJqMX}{di|4ORR%~NZl{#6!%8b&Qga9?$J`hr$JySupVB{azbYAbnNkbct(e}=~ z2E&1rzUsct00kLsH1Cb#0BM#m65Uf0< zDvaZMg%SJXD_c~Y|5jXt6Wn`budTU+j20kK_JdA%8)d&0(wBF&4+U*N0IQf2fw)MK z=NFF}1s(|m6ogsBTGQ*A8i^~FyVJ_?KN4bo7Gg}yWiL#$ZxU7rgc4$RuvuUG+)4-W z-BD$8%~hC`ZPna3)O}&Wmp3R`|6NM+nY)Gx8=3+N)rna3+zVTU#DS<_p4_e+vjxt9 zrC|l&S8PPMsbk9hdOx?|+mwU5Aim&+nG7kb6<*DKM3WlvwlVhIYV!~T@51q! z>eT$o+~eb;W6Q0EXgY zI4>@`cb4OzL}e_=R%P0I=jtqQp#Z)(K75}G?WL&TT z5(%L>Y5zpHQ-e`W@RwaLN*&o1=v$HaUg%64aFdIr16>4$V(HGhu#WFrw5ptqz;cZZ zQ+}b1?vYoEx=d1KYU$N>2xihT$zz@Za`>O5u}5#6`hqeB7WUR1-2<#u&D2x|8d#aL z&^t&Ull=mU0uPzRf>0r6ZHuSIV;hdV9&CMs10B zH1#uT4+X#h08x(hL_&M%IBb>uAMx4 z41^@*(l_FU)jDt$hgrb)c8en3S^A>AgTohDeN6jT-w@i2;9Pl$WIuXMcd&Ihjtbq z?~aA2DepmYYTDYtH18^o*TGn0SXO{l^}?kntL-eBu3*{q&WW=fF5Is4Sx(c}sk8K! zr6T@GL{ZYj!W!Ne%?%(vqdxf?uPzFr7@EbDj4`?H-ooX@G9xrNsi?MVk*M3~zsmvSuS^Ebv0 zNp?N1lD|PQx=;_cM!C}63Idv9J$_Z4WvW!bjVgk~hVQTle~97CVq?E&cM5&4dY3Rq z+>TML8c^faK0lwq?@|T5Nt*;fM60+q9LdLMXVboaxW~n#5mK_>jUG^z#v~Ew&5ICW zsH{(sujSZ)i0WbKYbkoVtJ4Gzz9O!+piFgpF(ZQS=E?cg%|?aW*6*;VOi zQavep;_fWamZ?CW%lYPK(VHLHR*dfr6mCJudKDgZWjk6Z!l1iwEFi9hY22Au(n;~D}1Q-t%>!>Q6s{bya@9qhlFmTEB$#utqW zQNn&Ih_9umXU=Z7hWI;fTVY~*5Ii9h>#v{@W>GI7;6E&C za#|O?M11NiWa|rx%g5V3^-3!&n`!|jtS%V2m(R<3H0_Pga{!J#&8{2T?gx2SqOiQ( zk7NeL)Q=)ZraJ5a?-Ar*Zg{=e&bBj~R=W`{My%leKHL8p&*_ci-5amDP!0MTObGnm z%;V;LJsP1fzP!n0R`UU+EGP*5Qy{obU}={DtKG$EDbf`Hh42@Ni};Z$G9?moVJ*XW6OM$o&m`bScA2D*Hewy8!$q&OJ7Uk2bTkPv!Y^ix)j^a5KZ zI73*|j>?h5+P?PFq#q<^JOG(KWxL-EPW?;TSEH5JVj88G$>&rnT65WOQ_kzcXgV9R8yYUe$$S8S8N*>F27pwe!5E zsPT@H91ZM*>{6@6X1kyEgps&TWGfT^z*t@tc0%&N^|{w04ugIwbA>pH21 zig8x`Rvl(%kml-aY|*5FjoId(d4o?!FKtY;B)U+GLKJN9PkU>PIju$fjlq)y-DBr+ z)vc@NyvGv|NgMf9xM*JIO|{jYp=rX@373|@8=1urSC$_*0mzS z=?VS0iddECNM&g>FTJ%(;K4ApJBKD)eukoB4GFj`B=g#Q`Xoo%a>{YyG}IjG=JBOp zgz;XA;@wkI(}4$VHGq*a)UPpT4cUBHW7_`gAn+$HkIT!0QK08l{*Fn8T(xoj)}ZFL z5c4D5Ou|_cKioJI!`nkVu<1>xA@5-{OL$5gxcb(g@%5q0200`BRQgt>BsA4;HF0~I zPvIXIfOan{a`n=)$m^xst^YhNS|pHg;Fqz{orke%HCjEPyxd^Qk7zRt;g47PNZZRAb<|W zq(X`7m9_Gu?ivgsNIm&jqJjNQ3EBD>37bNd+LqyEjCoN8i^G{d0G=<&q0%hM0=9G@fNmc@?-ZW#3v4@;>`^NG^5p27CJ3yh&8E z(BzR4)>-`+lv9{r1Q1MXK2v+U`=1z$Cyp74hrq>TlW^7{+;vIR0E)Sm_wNTrK%--W zMO!yc`)y8fS1NtcZy!eOx76R0VDs%%*w53s#5sIz{n%pyPKJygwC-1qcS$O&V}5rz0%=Z6RtB%T@AjBQO!`MbJ5MTMH1r0vJjG?378da?<%I**1rx;$MROJ-T4 zc+-d<4Q`8s6fU@!P1>~035c#|OOB5xPvz#;&V#lxJ?e|IngvFxK6PEZ9ZFsIW*XI#uFw^$qp)VPCPpuV%o~ywJiP!MD#Y z93fr)afqp0Lq~_@v(H!KfPlC?=pUAn%7txXb(*2aobme)N&9YdttDB`^N~j^v^4je zhrB#bmvTO$crhIO$pf9%5Bj-no#nF3Eb^j3-=G}+;XO)8ss|paGqL{Js;O#W7jArV za37P!srz79(%g#1ET(intn5{mYr6AOY<+Xketz3pW?iFefegSWaXDbmjRftXM7-ak zpJem>wNkz#C;;m|o9cJwsP{#?W@IHEo71p+B8wQU2r^txo?U+-^5TjB`)#GIW8QSK zW17St9PDpx+O%T*Oa+s{se5nukGUK1roVQsGzR4+<5MEho&me=vWpA(1sN}EgL0VV z(#gqE`$A8vq##sF3q1~vaGr;Kqz(gQ%Cx%h%1j5@Ujo9fv*BibmFIc%op`{<5f}YL zd5+)5dJlWMe0@B&3-hy@0!%}iw*p22O5GSgWYZQ`%T)S|o259pcNcznlji+V)9Xd2 z3N7iFQrud5HSv`4^E>3QoiP7OFybv&loMW^VPJmv2C3ri7~%BjTcU7p)0Z?QZ4HlX zB($I{dcV=^<987WTwKtI-MW!>sG=}49B^!vdjtW5+kDpuhM!rfok)vcpA%2$fT!Yj zmKUGbJgaO;Zoi+wf0ve)Xy!JwN#hahc@2hP;Niv**9NI0$~?moU(UW&%s-W{U5~D0 z4u^YN=2Y76G}Trm-!brGi+2BUkNjlZN1+msWvwJBFjB^s;M0?Sj}$)JlD-23-F1C; zUuxcxq?1Sg{X-!kexDv&=#Q#g!EqagxCB6`#WwS0J6|^@wL50BF@8O^edb|_aEkU` zsxv_F5a5=!A70m99^8Qt9Resg^?Z185o5o2iw?5;S|;b+ltr9{=(9(W@9n)vIio2) zhO81y2DybF_<&!2$}{7|`~3F1;t$i`neaEMO_VUm)@OMs!Nw~=p*U_cgM8Oe!>C`$ zyR>!Uf|)_+%A8zmh39+?;!8z&&0W1ad{`BvJ3nicY&4^-AQoCKD!YWJ|7~a!dYwvl zP5p;B-mv{gl4$myb?Ih}@;PLIO7bR`BMEiHN4Cwpb&z(3qd#Eg^%6@)xKn$l-1s1_ zpgUd+_%U5r;ZzYIz-w^pE^pe;6ix9_e*f7tRe~uttp7vfR#V7Bph2V=eI5EIqVhUk;A# zo{fK`AS;+&xukl4;9J3iZR4nnnr{Sd0aWcLULn0LmdM~ z(rfyq?=3!+cz5f`IL`)=Oy_2vpy&6o$4cTrqOtGEU_ZZK{}hyY$cd^@1EqTvw8XN6 zp1-})E$P=`oNHinnul_2WpVg;sQtBak>(@G8!tr)et+Y`q_3~AZER`P8|uou#(uQHnZZZ#QHyT}FsiIU>?BK?7u{zQ#!M;D!4%mZt8bF! zE=ex8lD%}NGK%f{{++MxcJ$*9WaQ#jj*(C;QIx_v@2Mhv*JJ^Y{e%6r^vz*!gHLHk ziJVc7nWOV&xwU;CtC|}pH8sK}hAexVt)=zj4E{?QF8D7I*>%^T`@dD<|B~1LTP6PA zpc4PLQ{g`a=1%{UQchC(e`PJt{C{pvVHH(N!jz}!PZ4#EJB|PU0?XP%mxu6->FuHa zuV7g+#-8v86D>md*0|3-th{zp6|a>i(;ROXMvhHW_opb`!Tf4>BF@*))~1|?jLrb0 zuDkHi(ZaT%X|R}3x?hTf$=Ff(-N(%G@y8%7RZP4sNgXYz0{PkC=7rgil2C^ygVO>b z2dgJEwbC!ox-V9ib$e>L%cpD>Lz0#JLxYB^Ik4tn`GtpqWJ*O5uYEme=khYxBW#>< zVn|4{{p_=go~2Szz$wW72rsHwH@RVRupg#XydxLVmg8FPe7Lc&+>_dKrE`#|L0v*k z%1-X}gs&CMeiZ-?Z^4L1AdtiW4K667H(8x~X+I5?nj@s!+6dHa=m`>)8S8sU|KeTG z7j>%UlN)Uc*Dwh3E|#_HLY3ErM+~zPEsMBnmAky{e{C(3)=>YaMLU~P{rKzM_@5I# zY#8;8=433R%VCD+?qA$9RDY7HB+j?X=9XkoiH#@jxqr@m5e_u+pt2~rHu5)vm4Odx z73QY?p?a#0~m=l)L72gilPCy64jKOO#bCLb&4juo>fzU zI;Mzzj`!PpQhqXwT5l-tEf-6N=t2!BSgj`g+~N?+5CP*Cw%S{oa0L>+UFxK)g&IzX@XqKil+Rdz(mMNrDB@ zfn9L570Y-ToCQjp42L#pz!?X~iqnUs4?R5P97q<>yQ`Du+G)Wm>f4Ih%f2dhnNv^mHsBmij$|w`3H7~icNJWub!NdeN@6P3D`@RsC z;Q+E=rd>}g?i#tQS#atSwP3R1t@$Coe*e9_MZQ3r7w`*U09 zv?X{JS}xO&KGh2q-DRo)-fFnR|2TpwVR6$zp(?e{<}Plc0B<;1s{%9+)5c2|*x}yQ zOc)f!%d#ymQCXMg_Z)imJdwQ~U-^ENAhG8ypAnEANGoZR?ib*X}CwIQFf?|s6IXTXpS5vWjT-^ zAi0>)6TBGkanVZ}^b&7GLFz41_&p02RG~Uj?k_ z->Vskt~vimG>h*U`xz%ERT#gDj!#TGD%pDm)vX|mvVoGY2|yzkjceQ9^- zVc1GLZG7^et)#UUxU0CAs}<|P=QP~Y%l`_^ZpszKzM2^IUSz_?8jgSRi-P!&KuvPj5&SQt{jo){Tsb=e*F8}(a5tmz2Lhqg&TCxz7 za1qYfv2zqxJ5?>x^Vinh?LU@>HLN%Ht1OB5`n;PY$(rf|Lb>^$^SHt4jkrx>K5s$aVs z=pQ>ql7R6~yiu(w3XSxP30qVfJCukI{0twueZ} z@iKw`QnR529P&~TAM{wYC^7%b{^WlaPt>T;GSn<63BOEHXQ5==A($iEqF$> zGgThQ(r6;OY;|>aV-Fp5L7Y2szbPGk`JvSc%&hz=K|k)i0&C-Xi|aBaI{<3*;299t`#M znyar*WO9DOj{&NXD(r>dpMbTq1(o+G`L{>6aQmZhepd}1k#M{qN7`~K)9e^Gdr8A5 z;E+jFK#!fL%eC-qi~0|os}5lv8}QS)(4yy+^0{xJ1b;#Yk6n=&KSuha6WOtJ2ah-| z1BzFk@qe5EF>}JZooCc1mqgTZ>+s9p>zhCU8uPPjSFf|-N1-Qw*t`a_EI_&hoLu3pdm z{!KxhrB42a2>syAw~=qp(#5^yz~x?!8^X|g z|40~cC%p6LM%W4-zM82j5x02);>VIk=~JN(9p?8k{p^#A?r9tg`fRq*fFm%*CK$f} z2z6dhxCmC@FKqgL`sAb@=g?$d+9CH9{FlgPpWk&!5(AiY z_R&#kv(i0lY)v))Htyhsy5RBza3n>GEGPPnrV7bB{hPkL)ml9Uk+Une+?Caecd&?+ zExB{nkV1KZci&YV(w*Ork26HP-_3sb3IUA6Wn#O>6>49neBzv4s5?D{nVpti({$HL zbIIR$hh?+S*ROOkJ_m-6-93kvbdL%RPhJL^9jUl>=Q2f~tzk-{mH7(ix8<5N%Cwc` zOtFamO@7A3L;HlM2f_nVnjzFDvMQVSLMb?*5pp0_tTT#wJFu5)`Mb$r2;tq@Kno+(hate>cYm7s9_<> zy2C?Qi6~@$7n}qOmnT*OaA4ur?@xKJ1w*i&b4i33vPstv8_1Ubz8WVH<(Lq(OXvtm zBBZJW)$bAWRs0xQ@+Z9XwSXQV&{N7 z#x@CDl3AW*dJxB^ew10*>_M-OotGw-cQICV>xmTYEmb$1^Di(-bY}?IMjmHh85Cgw zk{@rY$wa=%IaIg$+x?qX(3I9!Cs?(Bp7UFFLIwT4%i58G~9 z1!T4sgX>Cz+Vj9Ym5v6K8DnS2IAq*eVlDK8~>!ZVU(;es>$ zS64v)|z7EfCG1Ap(sZYzrEQkY_zJ`;pfJqy0CHeiU zNl}(7(Wj|r5jRg4>uJdE0SDWIf|tVWhT==t5>GE#A-0~Sb5`5+ah6mK%a2I-8B!jZ zvU4TU8G`7D-wwn$1&7CHqMME=0rms-4d}S-VKkC0&*}Y*UFi@vY~M7@DK9nf+lG5b zfbuaXW`ELH^@=uck{_;5?77J73;2O0Dmo-P- zXBoJ_D_IREc7AoI{x5?{~7F3zKk!>KWTG6M#+h=)J`5oL$Hv{(k#!7RZ_?E8&(6QKkv^!|1@U5{3n= zh5iBSu7TV{hez=*LT0DqjKp^blh`z{zlX!Fs<~n#pzx>RF`jm`*LvwOtSU6G^YG(8 z5{im&8eG7k<%GM~{h7Tze?aOlUM02KQI8KfVANBOF^LAAnd4|;;V@ChUFN`uMXJ4r zEeUpAy6d_{b-uH(yib)vmofMX;XB6_0-u}00gy?3&(BW4iE2&N96)y(Z;+Zdh$wTPl8COX+O5zCw`i&c&SM- zur#{a9cb>lD_1jZB%it1W1nQ#`GN&mcfi)Shi(tKe2gMwVdYIQzCgnQ3iJ5zWqhA*<-01q2R8 zH01g&a2!w3NPPN*^kZqiUpeCpbW?#?wVp6mohg)^SuV12Qr7WJ8Kqp<;Ek&7T(0W| z+2-4_)|@EXgfLsbpQzkhbt#XS&dq>NZ(o}A>(_!RUgxmQd``>Kkq8r=sS96u-|_Z- z>RSngojIlHE#F_GGf-|vv0y+SrF_|xnWxbTUPh>&?($xJ9*)lUAIZQe3dGg&3|oU% zi>{D)q)NAA`C!iKx_sp0*oGz~In_fs4ZSfQJ`+e>KNHp5)M8Zu@D^_5AsevhFq(aG zyCiPn!D7m{-=Bara^?)Qi*J0?J5-6D)7x76n?!p^-S-RP?{~nzS1HYVE>zz1_4@Tt z$oz%s)_LhVjw_n?PD=xa3DOw=@3FRa+MBX0DS{gxa?A3lD9tL8nwo#P8+0#{ojDT4 z%Z=mhl78lnYQMX^AX0zFMy9nnYCcE3Q<&eLpR7*<+>E*Eg4BuSp;ZKr``Z9hhj=xv z`PPq;wCA6l*{tgZe6xAj%qsC_*LljM*bJjTGs^a7?T__if5reu9#~f(5;bQBN5iiA zQLcvm4~<|@R|A9G47KmxT(aqJjvpG1c>gKY)UH=z&B?7ZO-Za@8O*h~(gz#j9HDq> ztbX#(pyn6To>dR(>469kVib_p7@Ih)CE`UYME0W$Qe96xY(};5;OLQ+ydbPYaxn;T zT{BYO)LtKDw-hKXwiZY&RY;#aa1S06KFM1n)TQ=mg-RT3_Jb2y7JP;Q2A|*m3rnH7 zu#Qk`rb*O-y6mdb5c(lh;J29e?%YRMEyP$!*}~`V;H>wtvD$WBdkPnK&Y{T#K*``7 zZOyxzui{(|W}97$HxC$xar#{B97esSXAC_{x+%)|ot(^i*+#eX*2AJCf7}Yz7U@ul ziRe>uNJEQq93AcIHYGlMJMCVWuH`gvC#IUAC-*%y{9Abc3WF*)&T+LeHw|ULv~8)k zvurK-@!;~dz@70gIxlwSR1yK4DCk}=2GU7%54Gr`D!E*EJtix}#NHl@JrnxQ!D8M0 zW?gGU05$O zBEsPtJBIvHpJP9j*K&IG4>c&tZi4E@eq};B^mHZ?X-k3~J=)go86gkLSH^{BEc6^> zwY7Uo+)e9s4^7nskX*E+*zg!Fq*1Jd4y&OG;;G7;`4d_nm`^mbX}t645D%&*5%S{kcv*x-2&128be$zl)&*IyAmK0)ugul$w8G8_&EK+0CKzf;2r`uqKg zqwa)3!VOGxY#U7wXV2w92J=PK7r`*^{O2~bQWo$bY+ULE(o#`1*Jhe$$925LT>>k#zlpR~S~}-unH0$2 z?Og9vnWZa!9&ucecWc)&aBu4B6|SHw1ixL3Gwz+pniKp|rg2wb{Zs0^VapapY5#0x z_yEQR{}MNdUP;W1_xL?<=;^{m_jR%1&HF@Y>W495-%QP4n$;&#-Gm{Qjcex)+<=lR=+o! zv53q1GXw8z4+{2<@hXa<@KiIjV`m-(-T~{Gq#VXe{C+cZA_v{823w>Du(1&a^69q* zipCb@t^5xWQz+rFT-%7uhzzWZY4f>RsJQg;3Z(>nuU+sGB|L!%t+kRiZFVSLnHsWR zw|5Rf6zEKec!YCPahkg;4H9jeYD^|vY@tc z2<&E&ztPYa5^#8FfjvY%!nI;{4KcL|2y++eVPB8V`3LDiS_2uR;g|9+zXW7UkXO+q z8PF)}S!qBVt_Mp)|xX)ClXu|NSr2MG$LW(gI%>FIg3=+<*_W(ygF8;KC;5^nz&?aNm^7De0tifsgFukB;&@$T~==z{B9M7 zr%#L-zqiwHbDVn6u2|*gE_Zcy)HqT6!E`c|p(5tSha4HMc)xo`bWqu&i%76NwTbw$ z5aoFKVpApOGQm1&A&6Iaphmf#{b@0aF1==?W!uz((_(;Cc9Ta_Gh*aiZ2{B|;v#U< zi1)70x`{%SC5t1(e#r$-$-jDD`re47;W661v)a7uLvs-hc%>IahD!YGsS^F&y-J$j z*V#&?>#=tu-4Oq0wLZ!Cgih_=Kqb}~H6$yroeEd|hBk{mWjSD5<@a`yDYxWGi3`5r z`lp{bv1%M^9i7m|>mt-0E-+o<`e_n|@0(3OXwZ%*pc5$EUMGz*9aw1LvD##f87{`U zfKLifKZlfDj~|_eyEb<(mJ6d??jkQ?D(S+)`Z-R5)AjDA*3AaRpEae)F(r0-NbBO$3Qefh{=nB z6j{RdbZ7B=)`S&TxV+T7cmX{7ODru8hpX+jW)Qv#fOj#?XOA#+i3DyOq)#cTxfHRu zbC$fQ&85jJYSDi`P*Y#ExNQcviJ3e`t#lI)E@b8_S|xhH{Ir6}RAn*t7PmX@9mkvX zx3OJks47)OIPxT51J3pTB403+sby3|pdp4QcVh`x;dgRV73SR~9UKtR^37j}~wJ2N6Sy5nk(_Hhh z>dgAO>e$=9rMOmbclM>(Eb$jYPQbYhR1%jHmdXK&%64Kt2AT|U&Wl{359b_5!mx)4 zV#=WFe6h9>IK%j(`lEOo2jxw$=W=@>J7QcNWGb}ReD&1WNkXS4j$lwxuhSw*mK$wxQY*wAs;irCo#lqg?k(^x5zQ+8Um9B5%z zQ*ZBR;b<~+-^8AuaZchAKEO*0v8Ut4*`oTAuxfog#F4|N#4w3QU!_rzqeqb_lVgDZ z1?#2DJ6C0G;0Ft6HDeX%^5waF%TqB(H?l6O2;lIVxy{`Lki*&||Hq)DG$$zSwv zOm9ghC+9LyO{xWWr5`@aLq5f7iG_SP85QnbH-A25X?0Udf?u3fD}{+*avGhW%8%EY zYGcCzdvmEVU$8a>Ro!mq0e>hcImSIVYHo5SF0F`Bs(5Kb#jji1*FF=id2%BgKR6kwx4!wnyU~gA3Qp;XqJNpTmpeW+vXVTh27E1cI7B*9h#X^ z_NU52QieKk@FJplYXZ}N_3T+EH9K>idcs8_Vn#ejnk5G@cDJ)BvlGpK^tj^P)iPI! z-6QP>7FP2SH*+s6pZva2!TiMi#~Uw-B6*|a}$Q1nYlTjHg)eKR%`ZTyDeI|kV*FKL zzu&lR490h37Y7rm^O|rjeGPGqY!k26Bh4Kw*K67E#hd zgK9N36}LDFo!>dn7#Ejo%Qa?;junJDhXRipFFH|l2z1v%T|}w#t04VT`_{TlCQ)y; zSCjW&=`&^99rp&c?`>WgZGp(ajG;(tgQtzt>rL$`7;Wlbam=VViH5h?5$tLSpGT*=nv`Sy zF3mqsUR%`!b2!@WUyll}jqbuMQFB|BT*>}=-Bn?S-Y@c7Ekx^|HBBsEdRAB`>EX1l zY_@n=m3Heupl@(pMrddWiq%H~|r|KhWnL4?n*86%-{ZY9Ipd7{ z4IgoNRDL*Il2YA>M@M#>jvhN1BbE8L^!kw|z%Wm-U>^&a$-0H$?`<5_H4U@=4@*Aq zzZl*(ef1Re(u=OvpCdX3HhTLrJ)=jwS4{J3vT^cN+wEM}50m$ZGQ?HS)cVz*H=T*zZu}jxuM_VR2(1P@HZt@Ras~+N8JwD5|n0XetLJ6as+hyK*%LNJN z>9GRkD-)LeC!Vp2v^;gbk=+|6MKRew^+aS`e6A*n4~>jd*AmN?1o#hf)4>(#9R0DL zeLr0tM83X%{wa-OqGl$kDG6INWpmXf&!8Pv{GE)NQVWxG1|;|0?kqjs4?ll3mAMcm zr)w`#63XzT^V|@=YiSw|Xpb9OAfMz){;a== zTOoGBLshV>F`~7hpB4Af{w#=Cnh)7&%C@R$v+_x>uAb{$kFX59>ss|*x1f2;^RkCN z^*o?Jz1q4=m+Ex_)cc#^D))KqMOz~(!YDVN4Akpn;UDBk%ba{H=IIg6OjHM}ex60z?q?jPjB**SXdoG#sFbA>v z+FGE_m~LvO72zz)Wv`jL)`uYVk0dz+eZBRMLC8cR6}Gqs?Vq4L}<3g zKNhdWJye|P%G`64Q~>+sLXoTbtl#A-euZAY>V|&KqC-Wav8PFE(gxw~p!YXbp#oht zw0z2jf8~g8JvZ_CYn}@hdQIm3kAz6)8n33TxoNWp5MWuG!F?J1Mk*b__2% z`>lvoR*?Xsbd@2_qlKZo2bL>9d8nR2DmF{3Zwi^@2wXi&{#9hmw5wyOu)sB;2MxJY zVQ`b(zh7G}3$ut<@V8yOtF-2w?a#Anmc3%(Z0Q)&TUa;l?Uel9)=2k{B*r%xZ^9Xq3#Xpkw zi(zI|rd4KfJ$<>n^E2K?nT0vp4~s%Rzdo7RL6_@nsDc4RK%FZw%F+pM}> zyE25ocRUiZMdMFQ9S}cA|1C>{d13`^W%wYY`mNb{&P|_${p_{W!NJ|XaK(+F6+$qO z_`-d)uqgO~1*FbMAjxxZ{d6g>bRPujo;Wj4aMrfABn&=X@^}4zJ;!M-lV%I*B z1%!q8BdT2{N*)%CR$VRZ{>tpj`DxW;<;uzQp;mXmmZyO$Zq@IzIGvTt!u!^s$w?{G zyOaClqn#A@lHZ4(Gp__Ct{7zKrK1fEB;BX06MDnnNl=jcE1TU!UV*3v-+;`M!~fd3 z-56s5-fC{;8dxq*?d4}?wN3iXz{2%PScT`kgmnIB?l0lLr zp;Qo%s6-`|s3gf*vV!C!ITck30+Iy;B&%dek|h>7=O~$?$gzr8P(}IOUr+bUbg${2 z{${%0^{#3ExT{ui&%KvA_v~}_+56egvppnK(P5b-SXeNoVH%^e-o%yFkyPO_1@MOp zZ?f7Xx~(`)gg^Ued@G5)RGG5$^CObX{3h@2=Og{>Q#EUqL)spxgQHCCH>N|xY<1nF z7+Sn7^&lIC-Kh1Hz~xI3{Ju$VPKvp1JmV*tc0R|EzKSzd3T&$0wo32fpb^jasRfBz zs}0||2m^k}T+RDkmOrXqDe?(v#i!>K=gj*hcRJRYZO8buC8atK?&kuykK-F-q*B#UgCo`N%l~T;4K@8UDNvi%iZ%gY){1T&-uot{y;kai4jiM1P~5d zup^8fD^f8q$u)?7EBfz;bpC@@MOj9(IL2p1DZE-;SQSMQ-1wj{9N{KcxANdLWW43o zp^{D9d4lK_BR4*7d8!z)3+@O4+!DHb*DJ@K4kFV~IY!@AzpxSQIk!Z=EoyA?Bs#Ct z+3V(qn(~lPif6Xkt6v^*-4I$5_Zo)|W_pNM^;sU6;`LlK@cv+1!6WMb^%cyp~ z%`_Qr4aQt7NF+G#I|NtYQA%Z+qs5I)l{SA6oB38^COLs1eGJte#Ppe6_eQN z^9N41+3rey%=Te-GmpjU`BE66VY}!RFtIO*3X}2soxDy*TNgU;!kl?4cL(wJ5ar1a zEChs|f&2;tP#DhcGE*4;$al#Ib&}N%qVY9RZAxL%LFXPzB&Rm*a*HorW?jh^b4SvK zZ@keZ{!Uk9npcNq!vrkv*Ltl8hr%e1LE%vPM%wD(u#*>G@RL=Ej}4PGo9mS5IN#Nk ztiP1B?YCa2f+mhW=Ac3@&>(BFITCYlcP3=O2z8oWRrbDZZ_!0_linzSH(d1H*E-cG z>HKcqG)%%VUnVwMp&Fi}x`K-!7Smp4pf;z_arN@r>apD%JrADbH?-E7b~EAgC6b&` z$OxL@^HjYLQW;Z#uA7JpcX zjLAwroXsK0#!9HjKj_gqo$}C^0^5fQw-t?INX*~*%Q9$@h<=ClbbtLTA&rk@95?*u zU$qELU1O^OA)-a5`eqbIBnP}CDEw-1Wl7`fo>tX{T2vSHIziCmTQ{ez0d{VlcJOp~1`ZP+@pjHwV>(MH^mv z+-k=DyZo88d{1pdY+~v)*{4?w3-)Phffpfek5COLd@t0Q28!gZa1~8x=8a%8(RqQL{O#niUW&do+8lcq{7B240_W_~@mfm1 zzu29T(H5uPjZ=+}N-+uD-m^BjD_mm-394gNkzzIDB|>*=Jr&K`2Y#k;U5(edl8~q% zGr>x-i}cC$Rc)8Mi*jOxMz2(lR$;u8l z&?1SmlOxll$7m{4VImP}R2&D&6IU-@Y>hKjGTqp1yZ5G$`Q^;f6_IrIx_)Z87pUQO zfRJmc1w@VGFS3`?vAY0$@SL0Z8lwWMLIf@11`fE9tJlA)UXRjv@Gd>#lK9(Oxfhr$ zlyqBtY$Oz9hVf~YvND=;6c+mas=P))qH9(=C3Lh2($;wMC^+Im@(Fj@8A05%T~uwjfX~ZqvFx zT{@FJ;k4T#@olf?*T({E1>w&=k{-CQB8`O~e!~1NX8Ie(M`H|n-CoDEx%NR7AhveR zq{wo~^A6#M_Nd@TTs&Ax{UXj&+sl+?j0zD3-npNQzYl-H@@|R!lWV^c8>opB)~^Cy z=I>gEg%1CSAJ{2ocxBgaq+Zr0*JR#(tQ6vx!EvKiGu(~&(}pF+fW=Azi!I5$*Q@Gd6?gybhel-RHpw#}tQc~Yp2orj58BS->!)=8_vlwymxtO#LZ)f(C z_XXp!b!4YKx;digBVhs;=9i7vi1LSl2pHH}-FC%wkIHRj>AHX$hHw3$f##iMB~M72 zLiCf;E&{*rqWGaV@}2H0hq$f`0a^Zg^(lD@+Hfrsh^Tvj%R#u0j-U&CBd`zJ`Gf}VK0y8Ob=8w&WZE#s3M^UDo5k|) zNz)|4&tN`K(LM7)tQhVQnx}0zq-K#0ZQN1+-cXV*jxy8IIj#aOK_b4rHc?(Nkm009 zXFgbzH;YNAY0``yc7sSOz2A9R0a44pXZSv~;FGmA8GlY%{iNBM40gq57mK#-YJM~U zFr}467~(m`UDXu%Nnh8!Kpd_p&s}*m3boOh=Uu%xvJirpp)_NlR9hkozLChGY>9#% z^_n!wvuF?L>)xvr32R?DQ<$CED}L!7TXY4`%pw7K%sNz9d);1D7WqKL=(d)~+TeY-oXaY(@)uuY6^{0qg-sOW^VT)`n` zzEm{Y=xL{Z`uz!OcC(FpD#BQAnb~uvW~EYDsK56v{ z9Lu?Y)>)xrTVS-)Ef(~6?j0y=UGz?$*dk?m=7I*vs4E#i_7vLt1tI5`obdYT!dC*p2@P9xqP^F z5p1EeDIv#;d5Us)apKrec5}y=s$`+{W3uR?#95-Qh$x)=$%)mw!=N|Shu-;EA&4DD z$xp5vD~0K@t+ISAoH z2Q6RquOZ7#97U4ng67_cydhyJ%kRA(A(Shw=$Y?mR?CY^bC#U8It0;)7Fxdf) z+WG2yd{qzmykyK@<3U7xbZMGSrGIG{5)^~Gy)x+7(hg*F@45x7?Adj@vI!A?{JgNJ zo&H0;kM8c!mBQ|;>dG)1wpgKuwh`Gk!BrLJr>S!4 z=JnerV;ej4NW=7(6^)JqNfc+*booqT=?q`K(s-yU@=YfutUKEWD4}XweiN|BIAb4S zScTu4b4Rwj+IxJjM#THQJPMwt<)GA7)|i(hA3P08K3Z#x_y4CB`=|C9F@&a3W=H-gr=L-ncL zZWCv}ZRd=O>nXc`*>D_aVGIa3W1U&M0?u{yDSKV%pSME7uPHxPW|4Kwe$;Dq`LSrx z6!+=4p=Q*AdI_b;AJX`&g!*Bo3G>*gFs;ebYOHvAK0j9dV)LLTjl=I7j_UHqepR5{ zh9)M(l`3ZnEu-vuK&U)JsNYh{`L5gek_hFURbp>WH|hzeGo#ou9_m|U>wi12;`jln zAJ=~0K>9O%JfUn$A%vgdhp&}Vkf+^h%+P|-i|c)D;>6eeh&jIfgh#U;!~k@lbH-E6 zY+E~pjy0n;ygl=MDd(%oXl%DaKc7#xBDUo8N2^XhLZ{d?Cw_ZAGkJCck*?JFdGU7V zSpW8uPqJ7Z=C0HR@5Y>Z|BEa#=%NK{?JIf;^~$K`G)iw@a&{;A$&rnn%f zIZh8#;^ZQuR9f7u-!yxW#9ZpJq4E%dzj)IjlBrKd)n8G{-GCK`yu_%lL>@5W2c@># zUqO9Ta!r-L#JF=_c{$Qo6wjDm^yMLO{0rO^A@auwPi%=wuYUDPGw)s0*0lOm%*J-Q zl2X`%7km)TkS;!tcIoe9u(~20iw^aibLV`ng~@#-a-tx$q+LxFe5V}zz85Fjiho!-L&FfDT+FbCa*ozpeCBBtW7x;PfJ>jxP# zns(&(1x!@s0#S|r;uwoc?C#h{kpbV0n8ZCntRjBATa_b5&A#w%X5g%Cz5w=jYOS*BeqXScGj?S**D@dNB*}o8SgSBDuX@ ztY36~aro+lrMPmh7OMh9U6#W;0L@_-fK|q{ujB_ek|)E+J%bA^7S#lElDO>m1)pV; zacS{=T&-n!MDC3%ChOj$9l9sL-_fbkCFOLU)w^>9{(NLk(yb~TYGE`M^86sheTZX7 zW^l{5=38P$c2jXY0M-T9=GLMIcB}gt$zL=r&oBa1q z%0@xdn@O3hD0~WHjxf?$XqN3o820)Xh0CiD5A1#Xz(xK$uX|8lh(^Mmxj+;3NZY}N zcwrW|k@cs9W}jZ-peI4|lX8PlBa}YO zJvDPIhD9~i(IJuhfE!+4Vh1;oC|>%Ag92H_yU189F+h{LS!u3RZ1thXvQk(_X7KW0&ZfdnfbHz(5KGs(tF6a4jrLp}~4ux+(lm#ULVa(&5 zXd#r@LS4`{PpDQgjxL6XAi!<#F3Dx(ptEc;e(^)gihb#|jxl%BVR{nB9amdH=U*2Q zaH-z}E+sY_9jwXk@YgrzY~YhZ%@d;=>olB!sdFgH!`L>s0{_uL%Mvy8w(r4d*>v+A zoZ=Wz@!2Q@8_{`eOeT^iEl+5y6ZUmQK3Ju2^^O}2ENLOlzIyy5Nb=Kk!Nj>}Esg%K;IcRJnu*_5)%}Ly& zYqRlCnw0O+B1t{I9e!Pgz5pTxqN!R{1zopyS9kNG<@EZMi1}%8;A~d@W4pmnhSoe1 zD}^6S)>DTtgPjaII{&2u;z-L5K-Pi&(Ji z7|cp7F5G%QFE@O@TLxQmfqXMO)jWBb*%*jC_|SaC%yoq$RLl{RAK>LAX0xhrSkHD(RN_IFU?_u*S2vU*!QqYE~Zx_29D4Kd) zY5SohqIKoITXTX>ygh%XtF;$2W9CqXF|5C$ks~0{cCt>tP~p4#`&=H@S8H21JAXC6=HqWm0(yR_RQ4Wv7uo@(pU4|^ zk)!W+Ma&4S+csj=rghJ^4nL8bt46x)6;Q}_jlT3sA_JK zI*|dqru3v5^~9GI4i%s50~`x;^6K(Z*Vh`orlwrgPvl@|+ufbzgBuXz(Pkl4nNz8l zc07&!Xx_TXFVmNYkp3RU2fqmj zE*)p&#BmmwLDX5N_l51dX3*eD)13glv^@!w>41Udei<9H{@Yu8nE;9JLtjt}{HB}~ z#AmdbAEGtFg<4NQoZpG#%;c$_ttqw+1!%Xo-*|J+zjjv`|K1*IyPLHt|wRaBt&^!BgeD}AlV|ncVvDzvr}Qh4^5jMY`%H< z9nS!$WWC?tTX%B?qWkY&nzzapYj)(S$adpJOzdK1!IT4_7!VMJW^h_^r>q@ct2=gM)YH^W3Fk2yz$j}B$LJ1 zMZ8x`HDJ6Nn?n8?io`sLqJ2AG+0lG}(c+9Gfvj2RB3WJ4lvqP@ z$XX)tS;5n*u5pr2Z~AqarA#wBy&LpDXrY;T1mP^~M1xiakS1s=_$+7m{4is2$HqY1 zoSf(KQA47^n$La1n;g-8ST~5EidgI}KbUDwQQu%&QwXuDr}gDLuAlgzrEBX`Ey9Eo znZFkfx;O~YlEl_bgK?1Qly_w+1~1ax3#B3*TXR9rO3OBmc7N94H)UkjH= za0v1d==u55GmJde*3|yvU>;7PB6OkF`Ki}^PD=S@V~+C!^LJkpZdaebw_pF7^ZDqW@$~vHRr{>PN7!-OQpZ>pDbb>P zeVKRmj&*ALhOH(MQF36K&VFSBY zmMP(0SUm_Qz>F$Pu_?!n3Y^g9l8W#5PWYjWt7Q8=Fc`Ga&lMe+F?SSPWmSjaM@hC> z5I4$r4$?xW3+LaudXX`Zx!m+7%7_a-)1r^bskDw2yZ?DQWhz~ERx@euvh+n0Q&K%# zIAN!Kl@f|oS4%!Af=HFR5JG8(*FY~?(#mN@@l1EmSZpF`$xeBUT z*uP77bH!tpN@k+AE&R;{ipTdVb|euB;w6-sQ`wQ27obRJui zLoHTrP7kgV|Pb`T=9>Fj*Ho@}%@3no)?WF!5EQpZd?--pEre=QiPI$bJww zz|d!^d&6h<+yjL_IISMvmt&fpp8?2U_vMBeXSnrWy>3&BA9`cq#$tt`B){}68-xY< z8+L#{WK~m5cd@&+o|!X@->C^i&p$zb0o&Z@i8xeZ`n+*K$MkOcrtPk9ES?iR9Ma6V zV_e(bKqg!r5^GuYSaj~$(vA=#jgXc3TcV(+*Y#L0XW3PuUQ1;YxBiKGpnY4%MzGNoY)rRnw(sl_Nqgd?YSbe$iQ7op{MBWk3D#n zCKWHi_dlu)e!j!Ie~E6@4%bd1Dqvwb5uO!2&22!bx8Ym7_l+9J`);awZ@5W1ic)E8rJK`ye z%%NY|jT}){?eq;MMx#Q>s{_dK#1dBTnj%||{reLbooY1++u0So3=ij3jPT@Hu3#nX`+i`rT7W6Hnmsg--Q zC+HyjNY_XwJU#wbJyQpm-gxNZ`HOo4AHSo3DCBs#=y3~FYkxu3pW_gw_pW} zzj|5cjH<_e@~jRMb6`lOnw*kppNG=r`VTe?*37d`&e?76m7~pXzs5AW*uU#LTqAc7 ztGkuxJN#_zp2zS)gnPqyN#g)e6AA0_(Z7J>qf0WLcJk+&_rG@Lun-1`WKutt%RI?I zu(55H3X40(K^L3Dv0nf7nu7YL>Z&opCHbV+khn35c=9lhL8ieMSi z4_&c1#YuHOVX$xQ62GaF8Zn*9)KqP7bSTqcjuzSW_b{d~jP$rS-yK6UR#n_+_i@HV z{`4NGH{#(LQR}a-9^w&!cp9{8J92~=F(uIu_PcuZ_2?lDZHdo6WLdd$2?Sgx{!5Vuu*oc zIhHZ1FsPl!_{3%*G25}WW>#4DFe;y`&FzLWpPyyuwTS4oVf|hO;qXNR_dq`wLp4=E z$6-on@)!J}&uz62k~e=7c#(K)!-V|Un^G47<3W2=p*yYz5`hbg3-w;zEJF`FU)z~; zRE=`Z=MUDo9VshHooWN+Q1F*hZ z!NT-`YaCzBSoXo!MfjcGD$?AV&UDOVP3qGw+GL4P9zwEupYX}b8jc^93iQPYlNh|H zr<%ya^U6-A!}>4Gr%7#6xc!3j-VUCA8^Glk7CFzx|v?)j( z{cG;sBUa))ur|$7*a)?2FMxlG*gl?dwfPZhrg)pGUC2nuRV}6?CcCy)-oMFIgRbW8 zlM?cwR7XeQE-VO?Z1eMGY7OVrl$Z7^`7Gjtdv~41&PLF!%PHKJ4^Kt!eVeGpBexzFPO>UF}y{6;9^Xtytp?Cyw6)FVLo} zX*0d9l)QS$!~|DrM3isF`@=4F5FWXY`W}i$d|F*iFs&IcYAW8_vAU3Mk1ZOD95z=~ z3}GHmN9xXbI3!f8c{ocPHzk;73wTL4iCK2HyFb%VT)tUOQf`@poD&DK$z*bM0AA}6 zoaZ;e3V+?V=I>$DEA|RcGVkTiDDoeJSq5;1edX1eoGb}#Ig9)Hj*@3}qI{=|JGx`> z4|5$^)|J!aGI}&vlA}P{rsEh_!*I%Y$FXk(y<9&C0y0h}9byZVthrK+i{^z$4Q|pd z-HZw3kBMwIo+@2&r8O7%0^a@@q*1Lg}1SsA;J} zB?=4rlWk^G$tveIt!U$9dwbG8Aq|NNjZ@8`b>e%)7Td6yS%X5^F&enUhMxBPC9-8V zAd|#teJg3U;n$-1mWOhr%jkI|n@AER8`WFCE}D&#GTX}Xs__#1p!M|#xt{|2pJPjS6m_Wp8HCb*a(n2nZ*!hM?44HSlvol7y&V1}a=^M} z*mtC6PC)~*4byWTX1=H2q?oh*?UVjgudokHZSYRtkkmX~^${YJfg5kP8Xji_Z4P@-BnjL@GV7yHVzN1r&q zrthJFKC6zSr>(i#RThqK$VRRK5gx7_fY z_b$RF`NumSX+gHi59DX|0 za7o^7R{1mWB%r!3I(zoZgNM$29zE>u7?Tkc0Uyf5jqZlWnJdg1DU&2`rS3amz?}If zzLspsBJN}RbJaCn&_}*;kuPS}st_vU8GJsFICs+#^;wf5&t0IREASlm^PdX4{vJQA zMim&pe*Q(hlhuVBX8e7PslHQ7$5 z$&SsEI8s1gX~KZcu6~}JvwAASikrf!x##U% zK!z|RnyuH|g#-Ds5mzAmlKq#c*#BhKj`y_Q=Y4-zYF)Wq*3_giFJ~Q|tC+`;sG>+; zE2eAzd=@xUIcZ^)_pL7L-?)qJhpmEATdZ&g?3fM6)B*Y`U9tbXIl+*Eyt))&4g z!WN=x0zn4t$5;Qg14`Cu(UgecVI;6uGBC_Fh$$|6PT+r%uWMK$^_HCX+y7I?gUxRd zBLlqusN?;6LEylUIw zBwveAf#LtDcPs<(|^J`orpT{)Sq`#a}%oj ze!2Q@t)~B_SJCl5tLWcs6$N6fpEOH0YsNg-WX5RcJnhKw`V;@Mkn$Solo0pb5`ls8 zpvRU7k60@W{P+ZT0}vs*Q-;wuD7FbO!fIWZ)7Xe2oon`{rG&#^Y zBdo1h`!OQ`x;mjb2Lxz)itr3D`)$w>fWwM2#PM}9{JHM`wqL^Z;95q-4>{t4FD#2k zA2SKM=fo&Eqsnp)PaMc!$# zyH#f?o)rK`TQoV;FjUY$fR1TT+}uUhl; z8q=ED>BKXQLD02LI33I(HXKfezw7IP==zEf#!<{W$1L@rbATS<&{ef2&ercd4Ue1<8p#Txli zFP-M5wre%kRZXU~#@k)}HukMvnPd(+O1Wu^m9GUi*d%_W3}LHKGCIuPq;6P=rSdgr z-j`7=GPZx9HmAM65p&i1SeKKRC$6O=z%k9S-*>;{uF7)aQ?3uKai5NFMFr6ml=YTf zb(Db7$?-!B(bFBV!N#?nX-$$HvteOX>xW`HO<>jW^cxp%7;6xKn0QxAjhXI#Jjy=B?^ z3(fc@&In;&osXKA8cf(mM^&fJE4t|Ue-3s9CHhTwmfgTT9>-BRm*N=I>0eCbHP?K| zFgWO|kQltJ5~0dgAVM7>=`~FGSQnW|efg>RsuAwy*mBKi3Fj1>W&{>b_crpfw04g< z4J+@8-XJ5+9{@=#A?7OA%EHAsvoPEi?N|H&Caf5sURsBxfaugjYocoJ&XBs2L48Eu z6m4><&kLmdxWK?;Q26(H;SXXUIwLC8_WHz{B0CM@sY)(%!dAUV`$<_i&K|MHkA&?3 z1eoO0D>6j7sIYg9qSWQi*~1C;eg%v3Rf_Arl@-hXpaY`<>K^wcHd*RmaTDcXpo|lsZxf7mtWg|hPTQ}Ud zS!?R7tR0EF7FBHPA|8%e@34v9C+zm(k(=y-yh5*S1VJf$+gCJ0%oh)Lo{hSC@k_uK z=Xy|&$GS|cgjTsI_g=+~07@hkORb>LOfZ_J8^nNnGEyR=eFvh17EG*e&L=mUo&A!? zp%lvUR58Bq1<6ODm4e`hj6E3dHV`Rvc&WOqt?70KL>9po?JdiAW%(BXY^`HB z>q)qpMOu9jK8w#1abq1Ji>?}Rt-vxVF?3&q{ zpr<2l)z%C2e7XF_{n}ftBIi4$(_=1v`rxsjf+p=?QV7dejH4>1ALR}Jz@fQc%zjmu zMd2PM)f#-9f3i)xKJk)<2pans#nkB<_M3o`8!Iq~e00LQ zUz&-&!|J|u8oH+TLB2OJ;@ke~Zl27m0h85(O>2!l-tomKwXb8(UiS30-zuU8@B@tJ zbJ!<15JtNMI{BO6N|p{PGuc>W=E}>#uW(`~6R5-Osu}@Qt8UhA*{{E<5G4tnH zcX-Ku6Brake7}O^;X3(3Q+5KP^Yu}#i|99)6m%*DAaaH`kGk35*zX&u<*A+6@pR!?=aR)m64 zPo@$3@N2nD;H|YS~>w`8tl;H!rijsYW~+v(r23mf*@;xy0fU6SI+HW`hm03Blt{(`DI#Uh;%ZijShk)##0O zS5l1Q%5Q=WaJab$CN8hFZ19_7GV8T0M;Ji8Yin;4o)p0%dCNYfR@90shP1bbWE!yc z=^FIHj9T*b=R{m_KRjOsgt8C^@(bhXT&byav6S02S+f>LdmG&wfXH^^{w4ov)(2K% zi^{ULr3nA-c3IPQ#tDO?S^Eb_)@QW>HHZB)14d5|jtKa!Br^Au;z2W!%SXP1kcYG4 zl@{VZJxZKFv)r4}OO9BJiv=tm)>K;~fqo29Q1`QU=F&FRh?7|@cGzX8BjVzf)sW?j z$tc@2{+Uvh@qG5!gs$Qb|SDK2GziPhp7vPNM+aE<#3l9 zEMx3nCn{c5_TRg;YWY@fWb9;t#+0rmvS4oe%0i8@^SX++WVRCzNlfV1Mzmy@7$)lM zq9nJ~Vfq{aUg1l432bJae2;l=8Wr zkKmEi+YY`c9Kfv8HvwqCZK9rf6m1(!-JieC>9?+&*t^M4POu?cWMpLa^y}3ZuW13{ zjCPC4*f!TIn5=e=d$s7yWTtSd(dq@&r$1OzFUxlQy>i|vQNhz1`UooNbg9xk4x{|= zDJwMBjqpQKhHsBAHCD!`l)B)k@W67@^V18bWEX0#A;s%{FHd!2pA%eCR04e<&UP-= z1lF&rZwixMj__U7?>>uDd4-7>O}*$_d|mtVXUsh_qe+&wN0IQSh-rn&K!2f`YxTT$Sg}L6TuOSyX0-eCq^0i#~|k|V|++yamhCaiP^XBYI=ZI z_T(R4S#WEK1Lmj$Plc*&7oG(nTymG$g_a&$&{3IaPP{A+cV4cG;D04%f{Y@bkCC)x zk+IDU410VN9tBa80ew|pA#<{Y*H-h{n!GIGa)U9Xsj%p6|Jq=YB`gZ-s3!${2i#ql zODvYN2dg>jap?DAp`-a4V{E`TH41me*YU!L1Unu(=ob#R;V1n0 zc}i>Nj%!vn*A|){%rWn2egSwt4#|V@SAP?HWt}dLrohW<{kPE2F~L9W=>DTW4Mmp^ z&H;Jly?lI>!&XrW$_E#jlywTMc#7f#o)g;tYr>|#cI1oz;sttYxSXy>mRP`Rx7{!TiY)|`Tsdw~fY zNwgIueiPW6q}hMFKR+9{uJohtJt4P=iyYE6)&-bjwWi^=06)7gtlRuH`k+OVU19kQ z4T*Fs+Dg7~*fyXy=X;NReM^<1U6gm=vp|Ie1vOuHh}<=RPne>S9!=9>aa~9l%7Y2( zlBk&Xjeu1uCTwfX&DGz{DEU^=%}UzOrA@N^Ya#k8H2>RMumFUIr*#Jw{J=2_HNu(( zxf9yc5AcvwuU)XtGAUc8O`w$0o5N5oiUc7N?R_4YOfBx32vFTeL z-&aR>eNq+J)Jo6i4v}w_#sLPpNE{R9DKH6!g4yyDOR#2`#y4mO8^m4y^BcI)I z8=%lz*JQ#EP5~@6uFJxd_V_zl&j8+v7fxM~D-?FLIiUfLUbWr{! zZo}!A?o+_SMLSoq!6TO#I45jTU4_<#Tc;P$7=hg+RiogZL!hMB&nD@?S`ic3b=%n} z4W)T8fC~^Ra+!g@XAZHQmV1B`#$?e1mx^D?4Qtlbq{&C>T@^U03cp(yMVZ9&9;9n# z7!17$9g_lw?}~$2AlB7rj%cC;kNo^l!QE5@`9}uRyW>^9TsK2xA1pS<|1}DM$<$hq z5YGrvz-X_SIhZ}^UbzM@*jcg*0#yuJ3GR;0KPk^RbaC|KG@yP1V&=Q1;I_znnGTi1 zsiXPzqwBH!e6nmD#VGnGL?L6$wmvcBamD9qHHdlI7hk!wFjidsiOx#5A{Koe1EJ)ezC3aFfgi6 zj?Hd~237^GhE))^@5vd)t^1AlN?tS_I(Oj$k?FRxjc4-7?XXIv(A%hu4?+jkv3miR ziWm2ssv5#;&MU%M*k2yi>>UwY{jktW6daoajMFSIA`f~KHk=1kss_mdvqzNfN!fcj z{&5-GBHs;!WCSN_ZTJJEW@5K=H)JoPV^pX!gF%H}fqSV@{`N&&rsF0#FHt*05CvAN z7=;)*BO6Z9<|W9FOfMRf?!HxJRkV!YwS4kSg)X6z_y^CUp$FYGL9iRTK*9}Gmaq~K zOGb(xpgDDd&9)8iUuNw=Z3fO^!f9(Rr)343Uuftjn#t`B!0kU9!R}%i(ulRzREk$j zX&d?RuShNY_hj~kp5A!W(>v&b8Af#D?k-B8G^1cuP@ve4)N63EJ8tzn%O0yHr?G&Y zwppy3o!NRf)g%`|a0I#mc?itg*(<{D8Uru0PhBxj=ClC?2WkBHaEs0+P{-5obkms#|5rd{CX;3lHNnRSsd9t$!M9$m{uX|BMcJb&SCqd8ZEPisTo zX;!t`=jCRs;oQN)he%-?(C_i(An+j%FW zBs1L$_;nEkYd9-J9FmIMm8L&XHl%6vigyiPg$ff|>1S{VG&;tu`-uYrH5CK_11})| zmleL}P;T(l36g0bv3IhyRO&b62v8KS13S4g%rno2o}>pG6M}mx*Ts7c;vd38Wm~9P zrLOpOvlEnNM(`4*GU0-N;ND+TQ}xc@Chf=g&(eDJ4(kvgVRC0J|FY^g!D#ejcJY4= zcK+Aj|0_e!|4^9!-@D-dUby)GMKKwLmD11miB*jc6jg3Nzt$BvD12)3^)~@vuIFU1 zuJ3?rgo(um!_Eakn9NC`16ngDPGOX5#gj|853|vS-8T zRUjH3ymcK^>QMV{jp8Opr=+AUSI~ld49vLPbok$DJFflb{Ga~$*Js4P_wg}es>xnV zXR79%^ZZ5Ds~1rEa0Kck^DL(p9(&xP6&FY>RC z^_hv@k~k0;|3O0iW1RM1Aff)$+yCucq<^m~^>^9szcga{PYvrIEBSX><$q}_`BTIC zx3dzW_h`+CFQa?wsYZ~`x6h5j1O~?)@Zb%`b_EzRQ2y# zW;~FA=D1N&&xY`Gv9Xp3LUlHgU9g@#KbO+`j&zuC$&Rwz%PkAwnG|;vA8*e8Wl*9@ z^gLDXQ?7WRtD{->ZqHvgQvs+_BQ}Y0mQ@4McdE*N6YO0as3%N@1N)V={NE}l?)bk|0{nM&?qAC9{-L_~8#>eNbNJ^>?*Z8QU+JS~ zhCdC%YH^>00c8H%Zvy;>vNvTJh&?n281Qqq0)_v-_O3gi$t>H4CMeRR*C{PBJHNv)=f4G^B#b@ORYGOGM_4JA^(-sw&C9u;5>dnXc7y50 zT=1c{b-kygvM)ym0b+m9W5hi54G+I-;;TIe^$QDQrdQ?cH;Mo;ty3+f+dAJw2rFno zk%tpqX`S7I6j;J77x8Gp4ZicAWJ~AJh4n21*eBOzFBHyMVD!bpY8IsUizC&Nl$E>4 zUS?llt#2TcjlrJTjQ8X~R-bDcWjF~a_090S2U6z=P350F+c)DoMjIC0n_t61Y{5)e zjUFJ`;(pQaJi)too!zUGnz`*xBCe_(3sI-`cbvIstpt_uV;YZC;jV86Xw@{lQu}jv zaydRjee_2T{rh6FudVcHdctN&ko&5NsCJr?-w+Zc$6k)RS1yNORd|JYxAHK0P%xyX z>E`;)cAKD?#)8Hy@%p4geVn0zf%Ni~nVksW+F?_@Qn2vKhrC_cd!JAgzS~!n%Sz3# z!#ukAQZIMJh>VF4XEu9X^C16YB>;)Y2Jn?q{&@9a!SX_^-?NiRQ4<{_oUJ(-jf;X% znTI>LZYoh7t%108dUlp`sT;%SPX?o zI#N`6H6h4GvP?nw!hEb!x@ETunHiQ1{WLXq0UkF zvbnpm30st4poTN$Ykgf7hf<{qh5^&ERrPjRC#=JYM%$9QxWS@SE5o$3ssqxAFWNjw z$oAH-(F0YUu`!3&VM1g*OCT2sr^+{SM;NMOgCm_XUaeW#aSvF}393K1<7X>3wSPk| zwWl7L=i*0TMu-ocoV+{Sp0%$emic9y=oMeju66IKiYtAxRUhA*U2R|=&~RP1t2$)G zQqI(FQ>rNVIHTGGz_&GAE+4eyKQ?*H{ZkBN%8F4PEAF5FR6(o5G3adH%BqS}@FJUu z{{8|N@{Gm|)zk7vDY-@7f||ui{f;1ia0G+QKCX=w9E^JGH#KV$eLs7WJMk_w0*czF z1Nmfpazh#c(*%V<$Uq*(PX4G7PWC+RPL1)2Sbb{){gluUy)Y#++g?Gg^OP^#HE_#A za9Go$gD2kSX!a9Xlc5Dx9Bd_^xLlLo>Uiy|7gOOMTIJ%L zQl_)Gptd`AQ%TWdsjdf|XTD$*C;G&ex#2$E1)w!+;^vG6HeB$00WwHyoXec2UOyd= zXY0!~L)0A}+j)nVUNA+_`ps~-_05ULk2T2=ew_v}&CC;O7BUgKN69xBFT?Jm%xUPV z28H32#yG<_(Z}yD9Pamce9q$fYnCC&EZhFNhZ$7+y(=UayjKl6dp|l8_7!)HmwaMK zG}7IIsFg=Ik&)Lr*68Rou%lbt^y&$6U3oQ|@duxamEInu;GlVtdN8aqRkEYE$>E^= zLEVff(Gp6XD>sBcIzynx>M7r6VSB2~s(2W&OS(PE@>r8GT?@ylG|}DT9Wq6n_q8pU z1eD|t?&K|bNM_!|?L?JrmA55_^~G6gD^ty`0pn zXpDPmN`R&evdfw*e>eL=Oq`=pU;nPCq|X`pro9(=IB(00S5W49*1#972SKX7D1`7t zOyr~Gn%RmlI3}86>^1>I(6BxH;-AmxW(>uI5af?*ZWe+A=@?M#bU0;D^u;Ym0GfX4 zmR`#QYypSF0EGV86b~_d0JFg>;{X;Rsq17_fKYaVocZse)we6@H)lcoFOBRhfVm6j z0gvT8Sr2F&UuMzuvnl&MSLeTMoFqh%N!Rb{Pn>*|TSP{YpP%p_#=8HeLz~TtYsM

    >OwLI>svb?o0GQo&6ZiOL5X2$BYwYA@1J8G-`D) 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 bAjy+)VaP!xNf1y_lpr982uMaGXGO_DG7LG% z3~|V>@gL6l&bs$~@80#+y6dfV3ak6qyLau`dskQ0uIg&9eqJpA#CKKHRR9PC0G@$= zz||t)s|<6p2LMe?;5GmN*Z?|&2EYIj$O6bhX#d745KaL4n~nwmF-`#bpFCRN`8t8p zewX>@Jzdd=0l>}O*IQ3jfyvm! zlnHAY)CLV82E+gfYa1WWJ32b|u4Vpp{w@FS!_oL}-GLFFYgvDj|IYx4t(}hzXuJ-{ z{?OLP#tp>P0Dw+ongxB(!{B0aSIfR}d=6APsatCoPh-GaYt!+WP0Ag-8HxCdK;e(j- z;Xlc7_$O>_{qS#@*47Sx<3DTxOM*YFAYk8^oj_?sWn!`V&t%`l%U!_?my)#zztKB|rgym2GRSqyb{k zmuM7zE(Ul0#Ddn|Ao|UZrsd?Te*aJW(Az`rPx)y6?yg$b&&Rc#SVueczi_slkFq{U z2X#R6w|7!e2Qe{-tAiZx8-W;M@9TK~x~+g^p~iMT#@G7%*1^_JNg2eT z4p3V=cY{B5gMv?&!nMrnveBNdzn^uGADV6Fs(MWa{S5u&$btGKkldi)_^zQ0N4RM ze^UM`Vf6csJ9yLwf`A>s9pv%(yPU%ByLNy-NWb`-`bSwF!2b7L|KBBCfK~7p+|X&z zWznV3?}0~oFbkrKqf7i%j)~|mJu#Irl`z#XRWNV;MFDI;tzE(F4LJP=G!5{c9cZ05 zcy#~EhJVPzSj8B^fMbkdEMQCmhQRV~DSujO4uy=$%g{?_duzWmGYfAL*w&Gb(; z{z)giO(^oG77zcj3arV$Jn^qm{&B|%um!m^{*@CN3$23oK--{Sp^eZwfC<_Ht%rVx zHeKUCbyoT99f!YvP4BlyT|gV0{^H>;;osmt|Lf{+TdhILwFcL90Ja5RJD4x{`~iv{ zo`K#@4vxM|cfcOmj!E6!hL@X3kYA7=0IvJ@YaRgDr}*7(LnyxegXYx=021+F-*DZv zGF@{4fHeyMd|m|rvZH^{SoXl?^$Y--25tPj{r})Yzdm6AxBwB@GN=ItfCbbZjR)8%40UQBm5C{YdLI5FyP(v6YY!EJpAVeG@3sHvLgXlp_AP*o85O;_l zBn0vZ@)VK^$%MRx6hkT?pCN6KuaF_gBxDh?0oj9`qCwH{(a6#0(b&=W(8SU1plP7p zN3%e4K=VQiLVJvsg!U3G5A7pbEm|8|AKDn&0@@bZArye(K`Ed&p*&D=s3KGwY6`W7 zdPBpY@z8W=9<&VF0M_*gbOE{zJweArCqrjK=K-HjHFN`X8+0%9F!TiUO!W8YwdkGb zBj}6h2=q$~0t`9~E(}Qwbqr$+2aEuWXpD4>LW~-WF0k#aU>sp$Vp3poV2Xil(*)BQ zGZ-@gGYhjEvlVj)a|!bh3k!=HiwjEzOB>4?%NHve>lM~VtQM?ctQ9O2HXb%3wjj0& zwkftdb`*9x_6O`{>|yLR>@yr<95x(D9Bmw1oIsppoC2H%oB^B_oHJY!Tn=0r-21rB zxRJOoam#SKaA$D$@$m4N@g(qc@tp7?@LuA5!t2Fb#5=(!#lMZOh;NSXho6LBgx`uk ziN8-kK)_BQPhd*mOOQlROwd6vM}Q(EBjhDiC$uFDCwxsZ_4cLv>H=1rN zP(UfzDby)kDUvBFDaI*IDd{QiP})((QI=5-Qyx>%Qpr=f0Q;kubQZrF2Q@c>7 zP}fn<(xB7arqQJdpvk7`qS>Y;rc!*)rIA*pAsb*p1j@ z*z4HWIjA_)If6J!IA%BrIORCKIP*A1Z(-gNzvXf(>(=0HwA&)L9dEzBJ-~&=CCcT* zmBls0jlnI!?arOYJ;8&|bBD*Dr-WybmxA{mZxnAG?=L=9K2yFFz8=0yei43G{sR7K z0aAgx0#O1D0(*kD1#JXh3yumA2&o8#3)KrDg}H?7gtLWzijawDio}Sti(H6`iF%8c ziEfCoiaii}BQ_yUF0Lb!c5DPE~xnN-<8Ia7H~g;~Wxr9=gxDxw;!+Ny@3rlFRiHla?hZlhkTj<_p! zH}r0&2EK;AMy3Y*-tBwd_Zl?OH1BGrY0hY|X}N3FX#?8o+G*OeIvhG)I$v}#b#-)K z>#phv=!NL@=#%MN>3`5ay036Q`Tn#4r-7eAyCIRGxnZ&4v5}Hds?mZmpK+*hp9zhL zlS#cPmZ_m>q3NNSve^r>6>|~uX!CIk4hxvYS4$d8SIZ_VA}edFss|Vkj2?V=aBi(_ zoo9XcQ2pVXhX@-*n+%&RTY1~(wi|XbcByu2_A>UV_UjHZ4rvY>j&hFaj@wR(PMJ=VKRbmm-%dS0mSQH*B{DZlB#r-Cf)}Js3P-9z&j7p3$BQUXorfyb#_R-i1C8 z9}Ay)UveQ*_r!0}U)KM%KPtd5pbAC;bBBEoyd4-9xE7=m^ez}Z*e19=iNX6vDqQ^SL_Qwguy^6bxw~hbyl>ce^)AIzIgl~xgi7ykclI)ZElSPxWpJ6_8 ze>R>Xm-0T9BsC~?DNQr2_Bqq@_~!>NtX_Og7f#Q~z|HW>Sa^BwW&JDGSI=IZXF6t% zy;gW#{)X;N+?(Sp+pOVi`RuYB`kbdZr@2nKKi{gpt<7W4OV7v5_s?G~Ff8bKC;qOu zkf!iy;YE>q(ZYMZ_npOJ#l;`!J|vf*mH3rxd^G1!r z2NmO$8kOx;;#FnUY}IdS$ZFziA+>?Eh&so*g?f|vq0e_ew>L;N)O_LnQq*{}@paRU zrsQVa=Eu!fEkP}Zt)8vhZ4PZq?N;s69mXA_ow}Xm%@e`~&cL3E*MQEBlzTpvEYWV5uj z?6Z8n@_3bCHGPe7t$1BUZjV{p@Kb7jkO>ufuEhh*o?FV0`pyYjo=5yprWq&M016(_?7^AwUJ(Egn1HdvAOPSJ{xSdh%>nsi&In@2pZS{nFZho++Vu@Eh5(A> z0l**v0PeK{KsK1!K#UKbufy;A@&KBU(BB!PTqhrUA;I4Og6|E6Ca9~ceR=@EY5;%> z@2jh`tgEYw0x)i$1b|krKjwYc+?d1wkb6C!2L`06Bd*W?oUU2{5^M}LJaH(589*a} zKuI81od6@KI|dk-fax!02pSX}0}~4y2Nw@ys38W>AW$e8Iurxrda@1)1@8msBp9SO z1@2&y=~`nkdyxx9ro6>wQK)FUp*MtJ6?*6$g@a2$NkvV=#?HZc>$b3nsF=8fq@t3t zimICWUH$t8hDKmWW@Bq-@8Iavsdi3~7bWChqd}`YB7wH)3yi)_ei(|%j_e`Z+Jf6KDJ4f}^((_qky_B%n*(4ZJlC=>$|15B9M zV6=saiH(c>JK_GB@P8-5>qPW-x&nnjKpE)h=vd%CVmur?;{S5Gngthks;{O1d?>i! zLINcL`QJYHf8rVVuy0{DUF=kVi(&l(egzP=`u7Dsx?IXxuK8g`t&)Re z&nQuwOQ$H+j^a6GDaiX=A7ZsQ+5fX#Fnq@Ae7x>vLtVYjU@sL7=Mv}WCEdt@(-U(Z z({MV|L*;nRyoP&d@tnE;Q6{FWwmhgss(eA%)a!V(MOmqI&kr;(NMI z2~Ke6dsXGyC$Y}CRyVo6zw1OjzSt6)C~ZTT@OiJFPSUf|raU6j@zE;JtPUsNoDzB; zt%oG6sOUYH;hK?_gS*fN0X9+`y89|Y@uvx2q~66I`)AlJRk_obJ~2P*X*tQ_A=kD1 zy1%GQt^@gZ{;&H$MZQd|tKt0guCkkLn?nX`s!)w8JyG$c!OFgcGvz&Zj#o2v-rdbo zVoTW8Ta7$4S_R`9zUNl}%W*a~;&!t`dXIR|(yc{DtxewG+Sg`cI z`*i4YsLNXDG2^_)z!gxga+bVXw{`_gY_=>;iX8`wYUNnj1L6LjG>XdT;X?->paT|W9^v+r$x!2Kiem(i`AZ@`Ov>#T$y@<=qF2CWXxjOuNE(vt zQbqL&DAThkbrwCIFm81E1 z1rQukP55RAyg!r)TIsq1Rs7vj-xbmA znu;H>#nL??}cW35)NDTI+^&ep5r(e zV(3fti)MA|KHomwi>=EW8%Bod6Dd^gHl!?GQ9@=Ty|)Y>`R-D4xOf!*Fp4W#++@=m zerlxYxIK`zIhM8ZSHC4_P@PE#3UuGc@Sy=m^>b_L*`8cI+Y zkKdOt0v>I<9N?!3o_6sC!_9JDdQs>fnoh)Y@U--Xf2@`Q?}Eqvea4o?{Hz76rKsLZV9& zSQFZBffeNe-5)9Xps5eKrXA?x>zWJ*zW9Sk(Ed?aSEM^W{{%g#M?Zpvcn zt%Ok;vBX9eI9HYRTj!&?W87#(I>C}p^70(eTD4rzc8dH)l5lT;^7dd0g*)!Q0*T0E(hp@b)znIG`yKv@Bl% z=bAuJD7ijs%EQEW;SCXK2jsvh*BeAe+_tpc;+8h)hF9N>(sl2r{07fl{S}{m?D+7; zXShM~zqH(NGTjyQ$ZB(#Uyi98BQPV5m5a{n3J7W_wkYu486A(#SrkFiKH~56IxhbP zGZRek34&#Qt?@rNmt8t&W^TP}Vv9J))cWcS%erwOa@<}je24Xu`lr0~ZlO2$6B#g; z_WW))*t@CTDbZnSZRw?EuG6rb8xIP~Ry!_@_j@2cUCut@D$&A2Qsc%W26T`uL-N- zxp=uYqA+)yrrK4z*C)j|Ae)+j?s;Bvx>n*=d=!V{jO5{s^R6z5j~uTDZYT?vWq;W& z3%}#}%YxJHS%-ns7m>GzcI3KNB{`WGr+u{&-Qub_MvpTThyAW!&ReJrJ3P4JgDaipBD+gUk7<$CjB{L^!TUv_1J?ZLceU+X;fPZ*_MtLXLw zhq)Vfah=TWcnG~kL`M=--zwGQGPf}2)esXOaPDnrnvhoiXzp}seg)Xq)oivdq+M#- z&vlim!6!B)i?6N69sMFZv?1wA488L&hvA+zXYy)d*4pr-4ZlE zUN^IU!ZN_Ew5j}=&#S5VSNhMEw{x4MR>h5AQo7o5FPcx85%s@EN6=30QU$5TCT&(YV(0sHn zA@qlw}H9no;Jf4L*d`j)6z3gcpm7b+gU zm{}&CZMl&hL#d`W(b~uK)#+pyO@P5ApYHx@9wqt6mPX*vAn&} zdihN(RUKhJwR!42?Oyg&oy7sSbTsWJ?yqLq@UL`8hl@bD{TnBBd8iIJZyh2%JjN1l zWKGiWIY-l2854R{7t1mW$q=yo{;Mn5@%=%Oii7e_#@IP7)FC__Wq^oMiBWzMIqIj( zraPw1;km3tBroyo;3Vk6331jcDc4a>*pchR!@4c&^o#xB@BpubKSxnz5^%1*$2jR? zf(j2utkM!;$#d`Sh$i0UxLM>9B{yF6fI_vW*DFHSlHX;+XuhKH6W+oO`hr8PBc}CM z*eyg)^b5w$pr-8fN(ZNgY;iH0kzo8w@(aq&IXWb(n^;VZnT4Kk_i9ZRJ6`rHPAwrT z%A(eJoJm-kK2mk(CVZN9dh3|<4&`)WWu?!Xn7!rJMO~c*$U#pEY}_g)2ltWWtScE{7<{(WEkgwFI^w*{yk2I}3}h~N%gLps1QG9HDH!SVVCRHk^G`-i5m zP4Dk3mGQ^)ad1%MV@jMFb%$fh(wT(!Utl7luI;2n_TA>O;rUnT0I0cJ9|4K zuoSyprdk|#A6ep#N=v~#;*JIS{d(PW#~v3bzl`c`VV7&*ioSS#i3tNI8F+(XH#fb^ zMJq6-zkf`-ksMmR)^{Q>vO;~B>*x`61uXA}fPu4l(G@TxU^G*Anw|Adp4U&~{l`UC z-jf3339og*PJE~h3 z@WtIHhc+KjmcJxyYu(NUtAj1*NV*rEq{KqK=#nty6dW;=DK7Ht(}|)kIWw^wXCEZv z7evX0GAeMb5dGYO%ZxIxj7md4nm1N#_PV>_Czz47%fa&H<`Wz)Ayx*LL-Tt|=lWm` zFoQKPG|?9RlO`rcmgHOxHMTf59h_%5fYC;e`?Q#W^yel0bV`#VM1H(yiy+MX@~0Ik zZ@ILI-GUp<2KfccCT#6VoGjX~hove8Uch|=Igl=nOtbnPC6oI6xb0K=Q* z3J9tDn!M{}mAMD=z5hB2uhVv~UrETp7+!U*IH}aCW=7p>}~$@3PvGHdhL7O^0Lb#einQtHD)`^d$e2jtT+!+>=aaWsMX28`js-^ z9Sj#WM@db3>S4Y>FU@|b5J0yy+#=mfzDdIv(c(mP&V$%8xg16m)+apX&UUtK9p>y^ zsP^WC+DNI>|BzZ*P5ZDlU)>**x1Nz)G-qWt*`7g?%0R-RRvlmlwlGHWmu2J? z5P5TSTKRQnkh3%HwB{F!b~b_$Cxz*%orDPsE6NbHix;wVPAx=!7OEX_J{~1bhN-jM zds@SRJ7|=4DP}7ttt_`Gv9OA;sxMwN>VHJ#EL`>#HxC6Am=D@+S{o#R1&nz4ufMb7o}& z3vy59sT#S;LMX<^*R&eb#dmoY-}J{8DytJ$u)gqhjp%&V!F13{A*Z7b*dj2zYv&{p znydL2DNb+#*lk-4D=bQevh9)~ zP;Y9^>_sHIqt!QB4Pr4h@9kE1yuB!KCOpR6DY2*L9B?rKRJdv7=%i1In-5*5O*wXV z&29}If#A&Srjfvud;yfTtRj~qGW{Wz$jK1Wp-m1NBC)uO(r6}v<&AfA(kP|$k&8|} z%UY$4%8JZ-Be~`|(Bxd=tcsJq{&^&>!&^Ne{%=@~^X#d?Az4TJ2B|GX-;b!HOBLm*$&r11s zyy4Xk>gLoiV$v5rwJpt;deLZiCC5sx%;np>LqP{}?!NB*Y_(%d*_U?q*%r7kVwr0? zZIoM-J5LNJZrSDyPst_HL5$~@J7+pfH7XZ`KeX7jJCmCtU0b224S7HqDrI!X(g6uB zh?mE33-1VZ#3z=zOsG3J+fu9bg>Fy<;L7QzV)vFg=pp!$t2KEwJ(Q6z4lm1{qYb0h zSxn8zsRd#qXvMrC_+j~_K=6wj`x%L{Y|axoxaTrU;rQuw4J}P|s&QIk{JfRQY3FPs z)LZczWsMk1C$6szpLPetmAeUIKUWb(Tmiv-#4q~i7iZMPmy<>z>$3b4ze4yHw@Ted zG+!I0&%5*F_8-r*sV@k$_G>{F49By4kEcRQ4?fA1%qXP_3*t-LjgltFHGXb8F2^1V zW8Q3-Z~d}M{ZnA1#!=ViSx--fV8OF}#z3bB?mQCY;L zO07M+9({`7k|^zVYwg5R!s#Fu^*dBP{4&cg9Na;3U~G%H_^8+C7c>#< z5K%64lKU(WD^MzMfZ=%!BgMJi=ce&yW|ZEX!~q`mlWK}OSUc@2&MU!p zHA1p*ER4m)@-|ZTl@r`0lz|80Cg;z+lx0y^M=Cq+ZwU1i@7E%#@g|0Kz@1Te8pwk= z&S-Ck4g55fE@{G21mND9{vYtLj_mTKNJJrVtT<3G1>% z7$`2?266GtB*DP7@}T`Q9*_2?1+B@YC?{KD&fBN7 z)e$@ER?>CFzXCs6K{w}UY7sS$DNmat-6TtXCGD#QzkYJ^GjZ=x^is+?zmyKvR2b!$ zpQgSFO?usp(l1p4`Yv8avG;6Hjo&%9-kd&cWYI%f#pNTP6vj9qS+vh?Z0q;CW0V%F zNmq)hXupawlP0~h^tRjz75s7CbT?XWUj0i=OVWrh8LftYUENHWTM3yjm32yQdCtv| zq83!z``1L#>118`CT!K?Ts)bbmHn5_TAhXM-2xH(YV_LTxr8rd*|gt>Fw(p@j$5ci zl1X2hmsA9NMgOiRs*KK=LQXh|CDHAakwYVF;n68e7VDy3Fxf$7x%rw^>fRUscNKQM z*7d2XObHBm4RTnhpevx&ig0`BGa}xZrZI!`B5#g}>1$0vO3IXWLz}*Hk~aie%N2*f zta{HE7osD#h@HM}zIoTyyzMgX1(5Ghh9$>G4%wO~7ikKUk(_9sBTBN`$sw+YrhS56 zF|ERH_o4v0ax=(g^_K*dG(!e__o;sdP5Pr^(HO@N33A!ct}P1)H+SPbwyy+lLOK`L z-j^Ns%u!58Yr}~MlpVZ$+zR9;!lwvayxnFn6GL(u?s&ZM$D%tZ#~VCIH0sX852}5Y z>mruvhDgDB1?R>xu%V4swS0yCAjuJ0I4W(1G$`|HiDRItQE!wZoOTJ8YLN==pr$R$ zexANeT$NSja-Nduo+4JQt_O%@~=j~+EAn&a=?SIQ-B62ubOudT~>24_aB zV}A5dld2K!8{{Wp%;?PNB=4`g3rqms)YIBbIdRTc2FsRM``j?RDq5uF@+Hl)$JK51 zkS$|Prgfm16PlRZB}dDOeBO-1h)BMu%4p6P&{Zb?PqR^0h#Hcic(H_@CiK=A!?9sib((kdcYOgu%peBI ziM)x|=NgEkQn(a7DFHKy(B$S(fL_$MFV;`u{7+*0g$8}(sRxQTp-b@_jLy%E!`r1D z_&q$hew)dcN&+Nmfq64ICN%XG>$ah zur5TQ1#*`+iW>&A5-Mo*60WaMEqd6&qL4pFGNG%lw9hclH%DER6 zst0iqPT|rfc>ovX%FyeGg7gk3T8Ye|p0r}SZ`n82j(`a`plx9`oee(V)qJpJ7K@J{Q1)!pF=#JlnGCF~#F*$sTrArgLUT{X=J z)1$+aGerzmbo11FiLYz*6d{_6l#e>|bw{`}?hl?7ntRR1Gf^yu~w;; zqzAFW;qw$5mIR24o>&nlG*!~`xSUKA>=PT^*_W5*X{{pr{ZElBU6NK2hsKS{d9Wl+ z`yD=ZF{_7O9`3e=dq-0Ix9DuJiu(Gw#+sR&7??*z+!%IM5Qo{74JJ-`!6lCeev0#en@{~Vn_fX=U9BTjs4a)G%mz`InsG^u zWGM2k9g5@4s}N%SQI}zYciwt95Ofqy0E>WSXkHG}`2EV*uM8AJoREdopVZo(7fI7i zq`(}{9S{>S2N!6Jgd6*XIk*aC6ZPE0Hmn%s@`$nBq(f?Vw{wU5DPvQrq!Em^mtV-D z3LZSL5r!<{z^!P_QO&|gUW$yecfkW}8+a4Z~vBF(acj)q*4D24new-=8f(F zvY|G9igS68&mnbG>0N*#lW&KBRNQTK={K3lnn=F5?ZXShLqiR-th=>s|>(@sF7K&ZX%!tIo z{5-S5Cne@?4lz23Z&V;RpMQ83*nJ<_!%Fy~Kinb24SYS-{qzcms0v5=Y25wPh{{^{ zLDVH#_T{~!ek0*tBJa|6g{bjf+oJ=#9%&y-kHu27D?ksCRJv5E-4(`u*%xIN$2~lE zEcDd@(wg$93{RA5!HtT39l8-t)K%V5sLB{u6t$#-QP)%{sH75R&P5vJS1vBgp1liK zDe_{^KawMa8TP9BYq&*geD2>CkY?l&_(hv^_+=rPpsmPQw6qYGc7Ocs7?bLgL%c}O z_aDW$a;NG!q}MhqX>As?iN)gHqP#-kkPjP$iX|?w>0e1H0*GkT*-d8OS@(Wh#PpJ< zFHdad*vJ&?%)+}@KV~^`x4I_%*KV)TbFC4APx;s{lCb7C5=b_=Xug_Vj+-)OqW zZL0I>(l0g-2o-KKLk?LI40|3QTE#gbvARtGd~-D42wKw8h;TJ68*N&r2?->Olcj=TgJ^rf_h{yI}hOF=h3%nP>FPMpoBYZ3-UvKFCp~^lP0b zjmTcu7TUb{Hlf5}Iqv_(5F;Gl61Ma$^9txrEM&__WsUo&+-ltoH@}C8Io~th>@$Ag zX4Dpho>`Wk>mnLt7nPU8*D3#4uU!N;wndlNR|0@9#lG?O&uAaV?xL`4eWGw(?L89T|G&W@ft>BUQbUupAZhmoqR=Yy5 zDP$=E_rPvsV53QTW!q4g4Chc2d5yM7{-P~uBY+rk&$?BPzlVCY=_P=Pbw?iWdYgge zO?b-*(d>m0xXtXw&LNxu>@=QT%#Vd1K&-M+X_rex$ntNhhm=Enmv^~UFJKv$ZwlRD zW*2@znW00LCja~%Iq6^DA%7$yb8Lt$uJR4!7E~i!QR?r#@q2L!NT#TUk=}}22=!Q z=u8s~x8vKop%bgS%hs%iBeKpFu7JEyKXA=(d<@>9K6*$LFIF3rk(`Z%_|Z@hQ1uZT z?vj#`cq7)_t=Hx&R{Vk7cHizPSNN&=r7&b$mU^rv(Lp=7)I&8*Da)3VDfRx#N&q`_ z2pOeLwbd0U7b6{x)ac68a|z;z@jb43v8*I$Q7N!D^R{<-ldB2gA6dGQbbJ~UZ;vFX z`EK)#h|c*Dhtyd9Rtn1K4Q#6CF4FMbMY7$3%Z}F4J%>2^Kr77(iyrQFCBHeL0bKPR zd9tE&KF)J(_T~n=SGDOs-%1K~^$K zC_<)aaXXCi^O(sc9qOTpFl}1pu5MGd)vZq37sSdE{@%33?F$KXez`>QsJEqC4eTj} zM1(W%vgY!OrzQi-sh;1SAuZUE@$__gSv7hdo(tRT>u6@0xH(q3>*`*n(x+5+dvJm9 zN!*rUn7ATAcjVhPA1Tug_PPh4@itRDLIq~E7%M7zF@fE|uZXEFRmzknp)hf+3eSttcaVZT_g*|1! z=G+2R?6UYncCDkCp`O&mhxaS%y-H)1Zzd5x?m9oy#oYOZw^Jj}vCdxH<6?vzKI> zYgR?Wu{{py74IX)>SCEGr(8eH&1@)8XQ&Z~&peG}hZD+uX@ear2EzyF&8@&b z+O3*Kv(_g5*X&HeJ{O=A+{&Hnz?0w*nRz6M)X=5~Q9;ap^p|XjR2npkc*>q4?ZzfO57#MJkS zHv5zmmhaJO-B-YKcOAmTR6#Dd94YLP+UM~`*@qL=w^C^{QkEZS!180!7rqy)D$AfH z9Ui;q)|J|LHaI0%yqx|jgfVN1fHkJggEy=j`B_Q6q>$W8L7L+2KJ2mDU1eRQfTwM?FKR!cH- z7q0&<#90va3QBJ{*zvYEB2f3EVrZvplTy*6FZJMNg8to0<|$a8dFqJ4NDb%5bEywM zHz{0PioX1KsT-#enUmq=E>33@jJOD6+zR7s8m*qzRCDpiwY>tsm>(a{~-g+4b) z(sx&$`U)WDg;%0-7HQ+EU-{L5!^MHIjfurxt}WLy!nvB5f>{gaD}bWlvTbM?@oo}v zUQ9YWofiTQ&Q#BPs5|)FKf@ceWAi&X;N_2co@9>sF;>oRi$#7HpAxfGQFNdem@9Uy zMCHvdg?>hMPQe;N3DQ~YR#}xzmofC$NHx+2v>F3)34_~DRXe|4vY>{zMb5;_7ifZJ z`^R6Wnz!GxCJX4RQ6ZAf1iK2-3ZG_W+sF07*SbGQU=zO3Of$c;@(zLB|Y#Ly%10#PWzjuP-?*4q^yt$jkxtR&Xf*-xN7j+`{@jW4T-7E# zCabaT^z^;$sX>H?gU;VYu7E^S_AIJ-%4k=2J~p{_wuVl%q8YyLoDgnZSw2{B=ag6+ zbJESi&0~MV%GQtNl#{h5dQrxg2#VzdH1Ten(k&}uX9g@p^lPzBlXRCBNht|lo;F{p zpC7$@)hs?!@dh~*>2Q%P%%A2^hyUy=4&Qz;0vkKv@snFL-+a3`ceBf@STO}hFFYtQ>x(2H_TsGzMiv|MC%ESl8h7*iL8d>Ne2|W-}gqb`8FbP#W1$tQ^5vAo%vTxQSi5|IW<#)d;tok`uEMe{C>Mt7l z(>i(lv-VR4;?Z#zt2j#ni)N<5=rv`mi`zd#Q9p?q<@=>lQYPF1nY>?{Q{Ce((_al~ zgMFP?1H=uKsadmIaghTtmK;cjb>mXgoog90v|xP~9tS);(24t%u*+%c(=f*!Y6dV8JT z5?T3FsNLttv8_#xpElW@NL~yaPel-nab@Q?`4&#H;tf@`nGohSbe%>oO14)}x;N3R zbbEx#{_}Wzjq+11PlaUy3^EKad%wg}y?bF`=A_y41n_oYG5pkkQY<4Pg@sXOv}eBg z*6<|ZuGw~KuR>`jw&X2w{Cvbto&Mt6fkauRlzH8l=}QyP)FE(@%_!?!1B^n(=R0}~ z5IhqZp+$9Xj#gPy-196= zes2k--S~M-C9{s4NT?n_gL$uY(xl9;BtGkUBRs-?LK4aB2u+in?`jP`vNZoQPY=Xq3TpHBl%}Ng$fIiUXt1N4}v1( z_}DyaPy8q3>Bw>HqiN^I-Lz zW))X8!l)jU`el=k?YO0s@|xLiKLDdKM#mpFdPg6cf6NJ|ye?zD$9P9mw`+)MKbjK%pIN+~?=_T9Kzou?;+pCjo= zUb~dD7O5~Cp7P=e7R46*(A@fonp`Q%a=+U@wCj>Zt>N;9^8WMkGFtKz+a#*KUjO%H zW-22*=K`)*fYaxFlhcabWargJb+})nqJwRi;^^t9J$0$HjM%NF;2Wx3elFg+0m;F} z@8G3|QzuJNKYtm=txbpwY@`?NA(?bj$8yG-_*x}}G`#(&jqn&}kAH*(L?_cQ(I-Rj#w@CjZ2yYP>&%2m89*{bs>q(&%_mg50>sNk*Qh=q z-(T#;O?&KZ2ma!Jvl8=y4aVnZu~ohl+F#ev%wb`-T>UwAdbaEM*=bPx{(PJf?rDMO z!g8MNrQGF*xk1CtE#n5H!MT-Pgvxzrw`%!@rA67MTghhHJY&P!3d7T>&pzh9*(3_V zbw!yLTHjyuBzX1vj-{F&R)zA~8daV1Cp@M7ihVZBD+jR@uu??PYP%3%^6^`*uni1m z%iUdE{Ger=?fx}8nbJ_VUHsVPyuTa#W?^vPTRZq^9??zI3AmEw)0J}w?mqo)lpWTa zezbw`#vx@h%-&n>l?OiKle^2HsMcyiZ`Z`Rt5iihAmndt#6@HI!}0c+;#KQB>-DruV_Q8_ssP~=;zF+P{igQ{H!h0 zW@C6ZSKZ6chgtGb%JX!Udr3Xi)Z)^aXltF}RXx#R6e03YO_4@ji3;@Eoq`q>dmd$t z<+HAaLT)o(js+h0JbSB(R&SLYV1;`HEbPsn$yP=s6s4Ja~1_P*LkHFcvL zRmHGvVCk@geeB0nx0&tU&0&El3GZ1>`rdFyq7xQNaOt32=n8mS>TOjSbDqM(c=-if z7+OCr_eWwz7Ql*Bz95d8u%@cdmiJbl`mnF`dws_JwDB{(Xi*Lu72JBtDoclGD*9Qy zOL`!t|q%IqZ#9L-C&c%9v1r!dhZ-)q*&_O(z6b;(>&i~a9>N#H7x%Ys78AmiSWtyd#D+A>RZcaF|ACYBn zYQ8zaD?Fm@rd+*Sh&1n{@@cvcFXlpCXu>9_0S<;vz_dP000@rr$AOh4L z(HV0{ulE09?>)nsYPWUaAPOQ)klvycL8^juNI<2D2#E9&l}@C$P=g}9L_k16sZvxR zO79?Dk=~>TB=jZ;H9!bwy1w=9z1F+e+WY#>Is24-{J}+Ll9~C`F`hBTJ?^oC{sh=D zDBAA`=$;#ldL@))!rG*{fKAj$wFXtk^=V)FXA~|MvlA=>Wk}Lg#j-r=So)UA85?Zs zDuPUXQ*ZC$*=Ge0Xm6y)Eyb6c0zl3Wx|J(irHX2cS}dk?_kYGES3`Er^d+H{v`Pr( zdrCvzP`WOhWku0d_FPPMyyKoC`S<5OPvuX~dq|mNo~|c5Ql1J_EW^vjxIC7oH8OOR zFxy+d@?>AO>ydc28|6L8AF6!JdoFJ<^t3BhY^cvEK2*msTw*R_He!-&>GDR~)GU;O z@1*CTxUWrTATxV&xmr~|n}Qn#ex|+tEjpns)s!& zPrM=!cPWY-lq28{CYyYpQDLu7u$~Pv?~uuW4qu;k-(qY8KSj=2#X zGLIPmJ1$7Nd;RQjXl~Z<8cb~}% zYA;;bORLQE&Rb+5+Wt^hZZG3c)5ETOp zsITD{vV58QE+Hz;!{QV6$<)E-UL|g{%K9AwhHZ>Blo{m%F0^w3iQ zjLPs~AlTuA3^j1zGfgr=6m0EFCp^9B24>%CrvCUE|9mp2-I?f3h{Mu{L)feE6sg(m z#U@%;p6+OVJAHfZ>|HWWlZCs8FXRn=8Od{~@yiouiPmuEx8u{oML80mu!y%{8J3IB zC@JHvmIZu@4{w+fF`B2Y=PCB!W8v z;tt$IH4J@h$~9V zi}aq~yTtXPYyEbjBFD}Q3jx~Ns4xJyccP0SlLg zN&oUsf2<*?H?%~9@S8Dd>P0JAgjTf*_zF?VU)-iD)=o=o@|0d^9f%SP%QF}WmLo_8 zv3G{M@Q+BxlwX0{GD-UNNYMy?6xj+1-d85;fKNIJJY`DA*Br4y);H6<_D=&H$aYw< z4-;8&x-An7=O&UH3!E=m-~^N3COuS!+?(_qiXHnf6X=Yy%Y1mLCh`6#-x<1>kB}99 z$4W)cozrtZJ{ehQLxgvjAoKP#@pRkV9Hq*MqyzGfukYe8H5s)H0%^sdK_Ezm_sI&^FJk zVVhv5DSr9swO2ep=Jc4KKHM#`(Iw9IUxj5LnEF;PGb zrt`DtBkL(=UwIdwUZut~@afZgx+$&Ijc32A{Mvek;dY1uz0>MX5_d&$(U<{3O2sCO z{X4Dtd?J(0tn->xu`Nyt^XBbk`JIFSK1KNy-$(N`y;PRDL;-pR5mkS4wpg(Z1)on(M@n@?ZgxzCyuT|2j5sO@&)L=p)#W0XtB|@w z95csPC%$Y&UbepCN%MHns~I%6X0?IoIn~{A$ekInGq~aWD8s_;20K2{?;_dEVC6FT zmq69GfriQG{2`*M^_c|YD;LaI+|vEdRCxrg^+K3dpiC|hu*0^4!f|q5DBpp;wu6l~ zkF~v6wf*a~9W4ks@k)w%iVnT#{3obm&3uL~u>v>|VN{8LNY7#=-I)Rsx+Xw-WUpy< z^WK}eys>}lxHn<+2Al-9=eWseQ#q_!p>C20C^JuEhku$PSOV@C1t_6f1KtvHz%=HQ zl(LLE&P>Y(9fM}Zdg*S#HG3u4nm5SL(`@)Vd%irEhUS{!r+Ut&3fym$O70!yqGMxF z0ZXrP^tElc-W?Ud?Z?CyNIf$J`M91Zn#iHxs9zSRVB@7A!uWLig7G)Xi$yd#b&V55ryoV%lo8{rs@YgFmOW z?Myz_Stp!3U;p3%k6iu=hjdC@ju|3&id{@JOWT$a6QjWq##s%Tr$c1X-E0Bl62w!3 z-t}PNNH!{KilMHjA~tl{QTOm=q4mjJ$5R1geYLP>>(2E7zLaf2?mI^fy1J-)HRFDJ za-@;#y);fYK{qa*qtLyf!Mw{8fuW~CIIV7Ns|-E-m~sNLe=}b);{0kd3@kk7zI^81 zaNrq?r8UfzVT~iuENsZU_@jB`phGf4%+vR)ZsXQ{c_0K3I~OIIBC}Wbrm67fZo1l+ zz}k{5B_`{;y%{1aYg|HX=6O6#8qW-nF881b4cD6(%*=IJvRGE8zsaRohA!&YEwF9C zZXw_;wX)BOOV)Sf0wX2FZE77lPKk8KKGOpkvVnwFv~v*FI{mH{&Nte+Y)4%nLy*1G zl#^8p&1`HuJ7i^csn;e{x!0eql}M{DUmJNx%-XODNTvFB#}?ljG8( zeBlHJ^03O*#l5Lf6b`h^MXn-Y!!Fv)Dkihe^Z524Rsd?DRZNiSY&S4x4)~zz(civZ zdHd(Ys}9|VYZh-$K&Km7drm)(qY#RXHujeaw}`c|Nl2KC-rV748EUN+O9^{mSzPqU z#9CbS(fg~CDxl1k5G4*KLJ}Hrh~z@p-{82z%Hi={1TNTZ+t&CHd6~B_qnV4|e@)5! zZQ#9tphp3^=S?;8UoP2%6;o?onz%c7RHKOK2@pW+6NRA9W_AF?!j})3Bt;c2<5q4y z?2BoN{-r_bBN1oiYzjG>a`Dx4)L-`QiW7d5pogStT0R4$Rmwt%J`GkKUng}+tA>h_ zx~nSUc;h_o4y!P$Yw^$0EnO#b`X{tBr+&R(KQzaMVr`W;uf@q^TQwW{6ym*Um1?0I zMdC(Cb@=LA5mN86mZ@ZzT}!;*V)ObTyM}=Z5AFLvX=`03ykD!w?2}3~?(~Y&r6Ma8O zJ*8Uf!qx;`P#p-A#Sc5y(!MZ~>BbaK^6F)Mst0}AjS`Y<-io9Rl)?nm72o(~Vew;HZC*=yc=LLOu4TxlS$ljIokj=v zEQzBrxp*xux5G7!Gd)x=T|98G=;%`uIN-H4b01L_I4I8;;*7$IofMQjW^|poN;Pd? zFdln`%mycq0m$Sqg3hnVH~{jDL6PJ&h(a)6mdRkmvw!I;*>?oV^b+9Eyd3sb!Lcf~ zsNggM^>bD3vuJu;W@s?ysujz?F1LA`RNn5$YsOx>_g%NpY~nJTbBTxz*bPerQl}O- zKg}{RV4~wNYOddC8+vr^uA zIMWQYbppD8kiZm2L`a(-OSKtPEL6PRx2?-iq@p7TuKMfd53R7`zoA8-t5O}e|N z1=g*!vy;Zq?nAp<9DuUbH;j zw?2tFuV2#S6Ze?pBU9HT7bG796gJi<*FFgAJt&s^Q$n~QaG;XDzy#;E|pt6s@s0*&P z`I7;;_UBq#o3?k~BWHWJfpybQnGvWkTm+oy)bghJCM})xZhz#PaMEMl!mX>;r`@_p z)=S|T9{|o?>wO%|hCtrM^JHQJ0@9aihf-|g?CTOSXJ7eL-fHh^UMWX6BGBspkk{$g z2BK&C6L!i__s{66;DDBvGKV#t?Zo$wY%@%^OM=mHo%riy zv;OlO!F71^y9wUuXzEEVOk`fX=DfLSWqMMj;5Jz&rGWoJ&+}t@Z!P29J&}mKc)>`6wzS>EnLh5qa+5_e%vr83wku#H zf9z6rhcG?C5K7y$Y!0{-nnXxUWYg`Up6W?Au$uE^$uH)wDm^{BN*kz(n`z!!{jIbaDu_yua8|$Q?p{ zsy}4M-@POzJHSY%8ma!$h*W`UH&2vg<7zoiDm9^Z+Nm#x9 zgW{_Qr!8)DBSA>dWEy00mVD^(jcXSM9jxHHDYJ3%gR#d%2*uaneJN$L-yr5 zL`rZotuPuOF>_6?jFnZ^H^Gll$6K*SFlp?8D1w~`CnqsUw74FE(4^BANc>mOJcN@d zKyZCe5VMc3)FWPb__CJYUDowRksr10Pls` z4iMx?j9~y6v;(^Z96^mPqU>vMnOm&AoB26GU1LepYb8PB7z!l$U_>s?N z@#j2<^6vOyeTeF58;8c5&q z&R-ezSI>0LTfs* z`B*TL{GB~4FX*P}L~z2}6%pYTAGh(S*IxvaIP&+c6MM>O5_Jt!z+!}4O}xMxbeMO{ zk)kgB%AS9FqKU)kYRTl=U^7Q`$pzJ~g`M(BV_A(^O;p5(e#dX~q2~}O?$@8!XDq$ zN*S}{vT>)Y8lJ9~Wi^B&)IWE10r90Y&=xf2>iC**Fb!^awTh|`&Tt3MP-F9SLe^1I zfw`6Dh@-6$HxogW$D3uD(ZRp^d=Hx40+I?eXWy(3g(lA|} z!G#4vanSgks9a~;i)n4+GTK&?+EQ<_#LcfYvhlp0lW&F`;2azynvDz`_g4!0y!zbz zgn4v^HyTx1pPoyKSD7WBE&&EYH?&^B*R}Awc|-d`5%1ajYEM4(kfbd-X00iY`}D(0 zzS=nB@SR_v4A`JEmFkwjfcLBX_B89QH?tAJK+rGBK5 z-D)o-TJ_13F0}bCbx%);@YQpEG(CWpzAVr<=ErBzOJAmWcgm~l^R9Fq7Dh9U$p5M+ zG8vO@8?DOQP}Fn!6)2YF1{K%Np&n(NIl%)=O@!eV6LME&huZd1Q)TrnerPFdOfGcX z{?s`wh)3s$MB=Ji`)CO2KZCUIM4P()e8Hb8D_OrSNyA9d3kpFhfa#b3w;|SxkW2KG|hG0h*tas)BMC0h?lhXpVd9Xy)Oh zz}&DDRj=UI-ZXi*;C=Lc=-xKGBu;8x)Hc^$sIDn#BXy9T9Ik}n`Awm`UQM(3Xn zpRSJWc>d~p<=o}P)3%M)>+WeQjckZV+n=Y;4Aw&nlVyFDH)V#N^O$nnkeYE>x1Xq+ z5CWkE2)_BNGFDgc?d=;ym3YflVO)J=S84t?mm4ZHQd7po0I|qJM-u0tSC75H*an|S zK#`w1rkmx*e93T!KZstn-DN<9hdghbcn8N*fSy>+;EJ&NIN~i5r+y`D)m$nD`;ivM{0bn#JQwGpG8s&nuf&-D)7c(!uf{ z(m!p7Hms`xzT6p-6f)qC8+jRDFg0>0ltn{J-9iH6y6QM+V|`#QFZ*P^5w~OwzR2-} zJfLefI{s7e8z!+_D~ob=A?iD1oG%?I60caB>`K>n=Lu{%Rm=C`RGtQn!hH1M(`eAa z(h+M1Y)6L(Jpmzk0mH@nD`NWwA;NFA*jS?!C-bHtZ!=+$TS3h+z5A7=TVzP(St5l_ zkTpQ#q1%2ea&LqvZS9;lspT!~WaJ^)kr#O@uO`$hu8jOQY9J3D zQ9MgAW~VYpO0{O}^g?Kioyw!hSVm6vUfl(Y)RqlFtMKi%Y5uYDy}?Y&h6`%Wd?H<+ za?YHIP9&3G8AIjyFZ@e#5LxE?760I>0t-ilB5F@ZuQ2|&TFJ};zVGp>^Pbvyz-KW9 z<|_*Kshu62p33D~Mdz-4*%wS21_ts!+K8u;k7E_W$|mpDC5IuvkxKHuxl`9B%y@&1 z&^b;OBY6$;>LSnRimmAU5)3+SmZyB%D-B#knEJ;20G~&6cIY9j&a@mPY3&=!tyt=| zHpOOKNYys+K4|RmQrML*iNR{DlavfRylI6uzdjrkr9(2h!<1%%dtn!f=XqQ2904BE zfDM*4;ym*X*R>W?XHj9pw+(1x0#XV>ls%= z2^b8Bx)PLmP<`XC~eYYny8a$UQS!W-uxmi%FQjk8|4;tWyRwM~1LvP9*>?Fs?^r z|3iqu@P7});18aj5txo(c%Y&9J3ne|XN3oH>>cpla$5Zzcx$2hlL_frp4WKGB%*fh z^GDi3CIL^8#s05?#bX_WdM!%tu4!jL?4O{Ov|nH9VdYeQ3}23uX~4FYOt$n-bh6*c zkiC$JN8hQguBwRa@xWfU%ByC^dJr{+_t-Xyv!C&-(jhZMP{Yy<2KSxEs%S6nEJJT^ z7G&yYQ)K&T)ip*hy)q8}fOQhQ*B`AV5Kza5#z({=D?AGvPe5WHp;E|z6Hu|0ubN3k zMaGtQRppH>`Q}rNFy`oYk?;DH%^{tXp?TqXUuYRg71DuGe7GsP$hR%Dx~q1WhsS1Y{NSyF^^Jlx2dNB;-OOhF1na7U zFn~;NeET0w0@**9m_NUFT9yT8*}ONVU)2BgT&)~UQ9RG(d3try%Cx&jIJ!Zgv^B?WN|B9cJ zcLdrL)y^eeWj~J!zGkE(+1kf7rh`4^(cX#2()fL{@%*9dw0(Xo@H(eyT9ICOho_IS_Xk1vCX+RVs94!xuCO+O|Z_=ZKr-&i2q(9?eEY2IzA>D{G(XhbZ8J- zms5v3R!4;QIrW)!s$yEmhBq}eeCJ+_C*y6hRr12e;NB3izYMFzW_Z1pBR1v=x@hC4 zSR(s;Nb$E|gA^3|MH?Vc4b^i~Es6f8T%^#Gk$#YB>S`{p zpCa@m<{&ij1SETWbOKucFuP3?bKze765H~OSMaM8_sfhKJa6Q??$2Az*M|e*uyp7;v=+F9a$_m+m8(e8jJOwgi4V z6iAQkC`3DHIKn1SZ&O7 z6Za?5EFlVY^t>c+l1i0V=?0W(A^lw=F{>*Hieuu9jL zhF*EaPb-`ECIU6b#Dm$tJ3YT{08fkCTG8vN+Sifl(zl(E>lmoxmYU?c-*~PR9}(sy zjhnJ!QXihPr!Q2(2W8m#@ZZ@;l5+F2teNBTiMT`X#@@uOJB*1whx>4(uga7x+;J84 zNL6t|j|j&)E0BgZnw(y$?>`rH(I1qZVEU;TY-jM~HO;npBS-b9 z7d`j~f#=8|-KaEG*Yd`+d2z9ljrM{9t6trcRY^JGniaqY&QHj;#qx(L1e#e?_J}WF zjb2=}tobqYdX8sDCgMFf`W;r4lBgXXI~s1;O{$-wlG*6ptm}101@=?E(Z=>MNVMoO zuC*MrAHUgXbL;7tzg2ChC)at--K-H{5_8NYn7MKaMu{UU9%r-OGuuF|3#hYW88&`| zNRqSg?{2os17waq1Vb#8wm6k|$8}RMg{{7e@58C@3wj(SxS$UfbEK+}L-%TGWVnb|-T3)G)e zMw$W49%blF5>rs)5XnC{f+$3OBf9S>sDQY0Oi$3?JJLN^IRxXfXwQj2H}*2OhjySC zjmZt@Qo%B^CFJ_=-~Qh?CPGaW8-l;4L1N&3`!U)Vn6P`twPV1M;V;u$rFQ?w8@&%u zAOo}e`|aOj@_Rx2-VMJ+!T((GXi<_k=St(qTIx6vx0&qDA}f)~XYEEKZwL@(H|?## zHc1ggk>)^WOpvcJUioKkf!RUj)z1O^#2k*7EzM3iXhkxHI zRpQ}ku&23mU=5#MfqPHwf(fQP)PVm4MN&-#xD#?oEE-P%Zw^4&``i}D)CHVGm@{}| zA_0gpYo34zwST%iXxjMJM+!vFm!5#6R+~oF3rJ6)TYycGu!+Q#DzTn`RKdhhi4zb5 zP#p|)1_)XM%+D9QPe5&eOR0q#i$1^u96kvE1k>x!mo9e5Z2&tZka`et*zn@log^Lb zmh$GGS||h@JQ8M`4$lHDWJeOBak>Q6K)@jdfgUhIN#dx#zxvnKUOfRBmuCLD?Mp66 zqX965x^S@L)5tBFCZZbn@7r!g1(-z=(M?O8Cm>#+1MLHUzCNyb1^B#B#1z;fcy$lp zR#pWcTt{~8H~o(dFSJSu`fG#|yNRvGR$r07=H)W#fCo^#)O??jI}E_!Ndkk%g#6pq zBLs;T8-)SK8<-dcJ^`_6{ONLU(f-%?Y?&foB0r4l0-c@*I>a{(pki$h62Jr=P{2sM zsK0MI`ZQoDvbMv1%}D~#4D9lsuSrwiPC!eYByEXp`rUvlzZMlS4LTn%^QW2D|5M`u zzaH)>;RCRWw)l}mOYq-aOuowewfMf+k{*)Kw$NWaPSPNv0{%4X(7$bY{RPr_7&EdD zMY@GL0mbD0{ne2tke`(aJ`ipC2K~KW|Ld&R+G5#zr6cRP!(J;&lYX8RAB`2Y3|c`z z*$lD27cJhK(^PRgC>m48iO8)I-fdZl>5dil2$6*T_}w*|gA~aMV=gs_p-T_Ez_X)I zvWWJaFv6*Ru%Xy%r))ibH2U3NMX%5wCt&8Ch_5Wm?=xL0NPy@>wxFs26ax}4W>kK^ z`+FRIuZQ3J;o|EZ7tTY{V4um5Qz z^Y@tNgg{UF{|{LA1s&;A;_hi6TV~Jo%#Gm8V}HmO(%1^XZ=2`-y+F<4Nbm?&0N}q- zrO1jyg1c9Fy!vCvvQnMvO?f|4%BrlGt!3s2oilXOxZcFCfWbof%ZumAfi|BsK0 zWBNM}A+n=5aW%teI>SG?U?r*qfch{C;%jXxgkQ0K!s;DtvE8DXfF^68mW7pn?PC(=UZ;( zz;@V~1S&N66&{u?OVTlY+t#YK{qAQ755E7S!K!-^(ayX>NtAMJ10QSx$y!K&d}_`M z*(yU+1#rN7;Qd2glB|{M;ZQ2Fk8r#+ifrS+W*)K*AE7dr(OFPTdN5G;v@d}E=vWY_ z1(i!;ufoz3_df!BB!ftNEp+sC9SPaFNlys1001>N4l~`ikN@N6Y5etZm=n->crwn0ag-0F2=EP%N#x z?lJXhP-owcaX%Q>({vuW)DUq@N&-p~07w~{NjxPf;5%|=1xokyf|7~~v)Zg6#aRB#%KWZgi9Ag6DRE-5wfhQoffQFg%6+Fwt zkENJ(-#ekaa`~4gR~ihFk|G@y&YZ^mE1|TMXsJmbPMW&H ziMku9&3V@YI%C=&O-q`LCq1?Yu`^M4+{n0*cvtRn2xKs)Q3eOzaKt>s1l+=JPa&PN zz2D4MQOI(}caUk4FEsOUtNC|^A{}56!HRfpbXYlSt?by-n{0{PQAg#DoPvU2;WW@b zhe&UuAR@Otn6dxTa6LGyDH3f{qnS2+wXNt*e24Dy3!n9%90xAoi4R!XuTCDSvtbEd zu7qO|{=lp2!m?#2^!adfaqqfIXVRcu=aNVsZ={L)=@8PX1UhTKvb=rAREJM-BDK*~Wh zn57kLvl5GDbKO1rt?r?b+SbcVvB*bLrI_lujHiwEc=`=xJZEc}MP>G^T~*mryD0mY zx*RfWVF#}Ol1fh%u&X|d-aL2+#_TFKS65E(6~*1j9=xTUqG7~-#zf=k*=05V-Ga^r zs5&k_0v)J6w^H*>^Z^~KC>Tx?eos=dpR(V}xChA%5g`;{W+DTxwGfw9ny5~7U=1bY)XUCMb`&-;PC2@1bxMVDfXTSE zmUTlOuhD+K+a1#c;=U(j!dFq1Dg1%qHRF3X_ggdNo9)y=E)ul5vy5rwYqg5%+imOB zg1pLgkxpIUR78bOLxJ>=^UH~9n7XcJh3AS<&*ub~J!CouhKaWb)amu`k z|D3PJauBUQtOdwbc7li#kU5A{qwlT~v)lYzV@^M(G(bu58RcX%`Y>?U^6bYAj7W?^DYKIo5R|`c7N47MmOj~S?wA)o zWiNF*(v**FY4IYRGJFoe&pM)_S!&mLSgUblDB~JSyqVPP%if>msmk~tY7uEcK{aZD z$2fyImJ0kmT?VsNvs-4Cz2Og3o~k?dNu-@?G!`lEj6c?~3%pF23Bm?xw41S_W+OC5 zlpuq>)~HKH6W|m*Uq-FCaBW|js~{$_ojm64i1lN2P zMe4OO^76?3tX@gaFVZ_fAg0#Q4FCIHAOmgxdr5jydX%adfcYo1{V>O2n*C#{UcH-c z>iJ$KZ#zMNuFK{V`E-LZiT%Tz`#b_jsT3505_W^KkAxjKd|u&Fx=kwYSi%h~bQCk* zwoA2yE;CD^?ghbD6hOpuKqfg7W`N_)4CyW)n((W-1UppR31~+Qz&9^so`87Jqh>Xye4;6gD1M>bLh8sqX`iI`kOGGm~4=S%9)hS6svcOiBf&UxjNBfI(E%n7ZAT3?)D=!w-ROtR!b36WL zKd)#KwcA5L3J?DAqA>c_b$vDcKRl|GC&Pd1cr4c8)T|%#W-IRo(UdNw$Qgoc%6QyB zSv0jGqvaCRW)5+_=$-)kB5oOqWU-C6+jmJ%UOx!@Fg%Drn%Cm<+DKfZ*-^PQVdDbv z0yj@b%2M)MFRTYw=ea4RMQ^wUUhsB(=w4{LDq|Ks5i%%H)M)+wLR{MeH^njLJHK3^ z^!X>J_rNQnfu?G zh#n|{;|YiZ*)O3B&|LwEmUGG5&&@0=c9E+o=72-O7#j>co}mdaXO|(!hy$=X5~zbX zM0(bq4?OTri%KfF^}55s(Qx_C(;$ zIOsAffFhmwm1g)AiYXuh4OeM^k`7Vh!n=~{rj*>YTY}?ZD+J>#vZ9*74)?V1EXR_4}fF9TN)Lx!yUjwee?DK z&5=lUNayS-hVScw2(&@sOWD2zEur%o_AXbS+p7^6oWrXoXTn%F#o4J&POan{al_!= zeX79%^e}2J0|0ek@bvy4sel&*TFNw%HX->Tw+V3dX;J?gHts^X&n;tuTTabet86t7s}~Di7SA zN7`*}5#M~+2P|Zk^_>kBp15CK)z@9}lMG6CNOv4>67aQ-oqKIxBK*tjHt3vSZ40`9 zrF(-Ws@6UoG8u7I`o37rYr<=C`E04ehWmW1t+C?)<&P!G%2Dsl3tG7|8nURsE1sO6 zg&eX<)lyXMFX+Vxw92X}Mksfh?IR~7Fn#g$*4P=^wP1z;-qGyAxyvR?Da=tXZ*%cS z@h7Ahk<*Z^bf_UVqm;z(+IRcWB^9V}9=5^twmXTI^kp3n83Uh;#9_#u@Bu4Lg~t=u zXE?g$392*Pa){f(BR$z^K{Bz!quf8sE0@DliF|>4f z?re0kLt!axKQlbdw*yT_$m!R{?ceOb-u;D9aV9an)d(6>?Gu7ZJRXVf14_dx-wEH9B}EW14j+__9+51AZpTOXv3KLBLP; zykoYmq{jDn=4USi5500Xr*Zi>-)l`VGh9~T&2*m3Yp-`Ki2Bg*G&=((cOH$erd#g) zG-It0s(uoq6~Y$W-l$YNAW_0jToV!#Op(@W6JNX~-2Q_6v$FeWh;k;zw-pslk|Sv4 zx91_yM;C5i_%`Zzp(}2IonI?aSLl*_s;I1#8=~{}R-86QBYKt)S3sn%#*?L8K_Xeq z4B(tEGjv*b-8ez9Po^77abr*G73VgeRtBFVIARY5`?MO|ycqzZB-W{+>vl3%E3aLh z=W<^gT4>P5h?hCyJ6bWVgd9g#7i*f@S8>EP3f3gDz`-A^t~1=obD*Qt*_qZp7NXL} zrcZd?NSKxBH{S13U%OA;DmqvA{7u%p+f_L<{c%aXs`%SR9)f)?pQV%R*r^o^Dpim| z$e6rj&u;EG0d^};3`h3?x6~@Dz`a*}c-%H7X(7>z05D=&=AD2BJ{pfJEWBWyF#IMp-X3hoKFI!DGmiJEvG9~PI<5&$f56oU zMvgfmcOC;_!*+Cp6(1qYIlmRN$=HLbEcG)}kN9@H?3P7ds!94uZ?T(2pVm|ffdD@& z2)NL3KvZvXtqn2`#QIn@fCvbN;Uf?fNOdJXA@z`AP-WH-UBG9lbOQ3*C+$NAyKan4iCzr zn@dINuV%%usDmn*5o<6CLK3F(69#tf=A5$e+?m-Smjs?4NgFi#JP)RFq>t21o_ns# z%dw;L8YvLkdbqt%_xBcvT3uE%I4^r~0aEI0G~0QlFI=%nU9(TGsymR6DruCM66{rm z18){`nXmL~DIO+pq%`j8O$#fC3>Jo4djoMH@%j7Kz%Yz-YZ{NgmFqk@ zRZJRb6sXmuU4hbH4{XfF#=O-P^Doyg#UN)rUXYJbG)Cck!#4uK7-x}I7Q{8j$`v|H z$DaOn(@45#P!Gtf0=Lja%&6!)_5>e3Hrpg!BK1(sZ351BF^FKM?vY>Q0Tsort~fs` ze4AB%GULtK{N}kpRv2?2Y?Q=fw&uZaCfRF6P)oHY=eK!0)7ks|=tm*>jy86Qm^cF* z{l5!u15raGuDnI2jQ7liuaP_1>#FTP+FT3D;w#0 zz3!7O7XC)YF)UK_V@JMh;!QS?xT%5rjk^P1Luf&P39~a7;G_!#?&8%9&ZgA6bKB-f_rDRuU1-x6m9mV`DT`Nhx;*pEl`wVTD70l!;L`pRK4K73W2LjW+hq2wb@N zY^&5)vIZsqPCLSHz#Mlf$n14k*@zFV{6$!x8x zO}Z&i&e+ivnXhHueWTgt;sXV*cK@o58QMVc5w9Sq2_aqZ`$my?j>*ppZl3kqR6<3Q zT=ePO*Pg3O0mTs3q`Gqgy$G4^xt~fCJ6nBeUHXaPeB61BE$Qx6E)>@WYaDjtjA8Wz z)(>!Bj~S~zq~NRT->lRp-=DGgG>=gs|8A5SxmkV?EKbyGEKRm8tH#xLuo@)Wqzryn zSN%z+E|NL;5Wzajt9eytJ&ph=WD5=tVQ88+A^=PAAt(4)UJIs&5W%uU;reDN!veL? z?e5a=;x0};e!p2W-X-Uwih8k+PMsvFxuT$Z44+OwLobr|d_P;t-W>_1L70u*uZZ3P zmr;yMipD(O2n|1N7a~VXj`jVFj+>SrD2fmBmHCu^kTlWbOXC!?@a_?(O>s5(wve#O z!wiu(BS^sfU|m(nTg+xfEjPc)2GyK~6krxHIA z_o?j(gQqnEVA27FHAbuZCJa>YsZYF{2)CWAX!84(5YC)E`$vq?<{3OuU9vgSF zLvpp>oa(0ebq}GWZ*k9U%8MZP#+Ut#`2(Q^ z==W|env7wxIUd&G3WQQXvE?KpN$q3J3!O!)A1Y{Dh|Rsg7cxIt-2wXU5+;Vun>!k< zKXlE8iH>i-J2gt;D$$PDCvD0rOXKWbJ|Gqbcf8&|YN@yWY(m^!q`%InncHj_S{>4i?osQ zY3U)ctty1>Ww}^^kM49+>#1Cw!@HZX?1{=Zo>&R;sTKdJnekMPuuu(8{#(JAc@(4M z>x3;v_idgx@U6PfqrsrzisMIf?ZMaT`!_JomA=$8L%JSek=-vxDlvv0RI6?ZdX$BM z=W%^)eGKqm*+DO5_v@vdUx)K=7)~stxn7wQ$_}9eE1JqF)8B3(G~k9hkyIP3h9gRb z;yKfNzE79BQ*0fRnQZQuHX+W=(WV`8&fZPJwJ_sh;SeyQCCFNT>~W~(mYEK<%BM|K z&zTW&?xA>D`(5en%}&@eg|SvksoV7k-F+GYc}0-L zNp;N7RjeuBU2BIr4I~KIe~ijEd9`qdLde`s^>eROdypkeiFlD9T@t7~YCBdT!O~aK z>TUPH+|SzUzP*>*Z22Hf$XhRN|2=eeAsPK`Tjg2GvKk&ANs+{mP8izKjn1r}eykc|rbP_@n;!m^Kg*}O?Ld_ z#eFqi4xyaFKl}jXCnNvrnNtK)I?5PVv6|%<)$JS$^Ib1g=-|&F< zP_*hqXx0up&qrUud{O*V2e;38F3(%D8F9m8*F625rlkz0BkfO2vO{FYlrR4d5uSr< z?+h3}99-@J`H@)M8mx9`Kw#y3B$N3bIZKlUNMxgl<(C!Dt=0lec`A)39 zY3=nXwf82q_nIIwhKR0?f!DTC9Z-$|+!Tqs+Vb{Ti=GbrLyr@d;!W#Pov<~VhXM!4 zHJm6_On{j8F(96jyV}EDFu8Q7rPPC4HdkDzE+z(jfNBQ;MNl02F@q0=&>5E#M>VxQ z`H|Pu`|Q}44za19If4uFe!wi(e74LTMc@}}FQ|XzzjyV0O@~QFCaT!M;Q}Feb|dOUIZ!|q zADo8I>`sG^L1Vpus|7k=fCwcuQj$U{4t@f@LcVolf-z|VsfQmUrdwo^8nsVA98+_kAAx`K%Y#%;{jO`tSe#W#SqlyavHq2Y(a z{w|+rUmLw2lO5^=XLJhi3N9M*6vV>|YHJ25a)lhdbf)3<-sSDvbv0b}hhxivTlj9L zOnPZ;Wp(Vt1l%W#>zSm5dc48=pQoSFDc~)F-{noMutIHX9mc{*^G_EAP zpVQU}-f$5ZWKl8ZU7WU0{fVmY{=C=egby;)Y^qpHq36|XJ*5<8`)roJwzyZ>^9Ffg zB`zb>JzonzK((lRI4!_^1NAiaZtf)wc;=`DcNs8s14LJ{c+%>W_Zxz^rioxS(D-~I0Se&0Q1-}MJS z!vLH!BXf>9-sgQv=V@kGJYS8M{>WrcDLQ>?TlwtXU~!=NeX4gPm`fZ6MT+oc2u^7V zg>HrIT%IdFlTxB%3bIyJdDmyXzeVSpX;GgI_|F6mb~6~mCG-0 z$*KHKr2%f#J)h&b%PvY^EWGFB?6YuOvo-DV*USt7hjvS*Mlls>uO`F$(5h3n4?!1eyQeW)x* z(%SaW0)gObn{R1~$;O^(6W%ZD%1D@B@Kkn_*sY^j=H^gqv zSk|lNEBsjbmi&su-|j+vOxcF{^^u*rR{BlZS;}sDMRAQLHqGZMt14Pv(1{Fy`uZq2 zXNHpc+8_(14fkt(Y?*eDPka&R%imC6iB6hUfL4G75%iYa{9x{iV`<+s+v0YLI(2vY z+eF=+lg9+oK66WON9(hdj%$0}@0QZlhqtW^s@2~!?|ObNq5+w5P-jeaED0&Ap3{9J z5c>&#Ln^v2d)2;dY;Ag1XaPM*xYzG`UmKF30F4e(d3q5*3uyf~GNBlcd^EFAOyVYQ z__IsM0+hj7lj-@Kdp5Xl4JTF!V2Jl|?+QAEN(;;)Vz#g1F3*PBdI9kF8@?vN+8yc7 zD2X5DL>TZVF#Uk78)J;nVc+UYH+Vpmg5s^gZ`avPtYbx{kJNqflM{lU>RKdp zaDM;%t45Wpw8EKzUDKi|HRAfaj0BIl(motC5HreY<=B9g6Y9SW%Ha)4dD+P4Ca>uld?GBxXk>=X#dd}mB$xdQ}9$F(lB-wj~!6B{L5!FeEP zHX0HamE=a}8I$!4#d2O$K*q6Pm^w!8Jx4#mNQzvh}JiD`lM3;EgsE zm=WXwWIUZQkA8u)%{1V$?7+LgsC{){j`AiO~S!DibwD(z8ewAC|^@o<;U&s<= zE|6UzT8GsXc4`=OR+$03@7|ECZsX0QYIEyQX%=7ROY8mdOCL8yh}Jng7MbP2JUwnX zvRja8*wp@mU!YCsp4h-N>a=?{Ci7&#*ZoBs45OcgrR?-vpdVZH;%J@n`}|2LhNU#9 zX{BUkLjiI#U_6ypeWemKqrzdooID-RS{;@~n-}L_2zl@m5#7wwv*Wz@s2XQcqEe_N zTWgS)9P>@}>t}9`Mq(1$U=LLkGl~uknO6KnV4B=MI?K4X_t^K+RlA(jr#;`Ve@&ri zdO|*Uo2&xJJQoB7SPm?eYQFvjV#D9ES(dXG9(>Z)+R}KPQ;m6baCzH{=R@nqd7nTEI zvW%U^E?pK8k^$^EH1!(cl^wHyjf$1Cm2i`VEf*>&HHL{+^LjI66h`CF#x{N!2|rO^33b<6;kF6+Ztd>qQckM3sk$ZWDn}a2E{gfw0fe?1lq$ z;|}}PPd>#dx4#vxUr$tmZAYHzAWPAAIy3mu@^Rh;hGug3$@*2S0ilH&6na&5Yay$rdY^jf)uWyh%`>I4 z#=mX=MX!^+iabj9_4QTvDi^$A_$1_>$~90)WG;~|4Tw1KBIvmVBWyJV*Ffkn$U41M z`UPQ~b;8v}Xy1h;8Vs9r50~RL(L3s0sjg5h2ao+(*@8PIU-Q*WgKiV8+-Rx{Z3l}F zh03!4ShKBKQ`#n2`un2%{8?VF%2yByi1CQSMi4I~h;mx!+J=Bd+7sZ1r z`&$H``8#UhlCd=gW^qNO8~POZtlMYgUkfK#oaIB?Rs1Z`X0p8tEUlQfa;|U27DZ~; z$fh}nf~i>P#$3rcV##~F;gj1ZOD#j8#}+g<6A?9251l!ibgn*@r8k-aCs#97kT1RL zCCUaTF`8k?LJ7=Xm(i&~l{ag#zaymCgdR1PYPfn6>@3R$enRM@n z0$HI07EBz_e+qdGHL+iz+;QDAYX11;)ia6`mWy|-Qh4m7L3BfF3QQK%Q0-;NB|jIe za2J?y(`{4KL1jnAso}QR`-=-j`OVL6+$E0rwnPC$pxBibBN15HP8eD3&zoX=nw|}~ zhpj`%=cTZ3rCY`LTj-WbTE*qka>+||zFx0IO`Ay*#Yy6?WVQ6Mt3X$zDs(2%Dj`k; zPED*lo#^=P4ZAsL`tn@IW1moxQWCR9>INWs#jo(}{uGX-%Q$(bA>^849Ftd$lz>fr zNLQZZmo-qEadfFv1cQMzN79Dbolwm#d*lmrTxft$b@S-a9!ZZ=vwwHBx7NJbEh7sG zS@B@eRW$0uC;1_CT;KvJ1{G5WX6s>1H4YiugHqn=_b7N|@?=+y=VHyPK+))oxNr+{ zBoFrHPqi_L?nM5Kn@^SvS*#Q9ON)xpc%*cEUUjRDP6M5sEys11BEk?<1n#YGn{b~6 zp2nK@z2C_3Il`~g@6OG(Pq268`?h~_IpJalF!M^y^Ni9U?9es}-Oh?DIqRM@?pb>~ z#>}qn6?A1Tyhv3r(}bC8J<;(8nC6F!XUHKxgl2EQX_}%EFxy(Eu;ddR@ z9Y>2xSv*d_k^rfKcUvZef($#KvP^SHR`uL6?}#s@%DfV!`C#n4$j`UXD|A*7^Ckok z4AtIr*|{=x-%+eLJxH_{9sgXRgLQI2#^M!TI2RYEi-m^-sgydb0ZJbI>$*bYgdehZ zo%~n63^7>aV4X3g1C?!Y&rUNs9&?W>#E3Cyl^!It1cJ5{AYi->wg+fth03&*+MuTo z`z$EujOTmA%S?w@+pKj~R`pnJmnl43Njqc#$21RxBTXn*|u!f$+>2lzA(b zCWgCbVBqUp^qC?*rPtJ2vPdr13QL?6(-9Z(S9xi?Bu=dem$uc@CWQ^Q`{|0JPdDs$ zRSO^E<)@{-{`t7aZvYJo{^s`xt6GioYUo4HdQiF*FP88Uw{<_FwA!s$_P$sjd436N z&|wkQCV{;#FNnRF>AZJ6;^{49p3X&S{RD%Hk%!DuoI&IlT5tDuq8`>pc4;)kPRv}K zW!2`ruf&#Y00QTO0#tC2rQ;ebSRJc`3eBTm#QCURFp(sip?}Q#r0h9yoB%DDjLVu; ze<&CU!T3H-sEuRY^2rL3C}QbL;eY$42kG9m{na;&GVZa3pWh9fG+AdMdpM6n998wW|YE$sf-4d$VcsoL${ z*K}2@ygmj4sP$xyS+qwmh*z9U_E>`M^n>89%DOScp(LVGnq$Lcee$H3$`HbJKLhN~ zP$-*6b3jDV#%mJ|7v`DpRLNM64}9KyD%ulG;8+Wi%V_0y`HK}zLgmLNd2vn&-jhPq>Cs>!lC4Nlqr7f^HgC1J>EIF#BZmhF*`K_9zZ2r{ zi1;dH#3@kdc#DjzD4Tkdw`ACSdR`4GIf@cU8K~A%rm}J+hCh+t=pZAj%BB?8H!$CmdEfoEO4Yo4wKrbM3#OrmD>ppvGG4 zM6PlC|CJc&#J^&sa>VFaHKAhn!iOIYw@SS)eqRYueM1kCi_FY2{(%&;LH9Ac)PbqZ z+X_pJXH_vu0?JVKkW}e81v&nBjB~LKT<&{92`tH`^uA@Hd8j07uI(^;ZebHT?gXB^@=9sm(u*0JG_k33s^1=Ff+d71k{ytM&17wH2x%x_>!7YJH}{PBM)&!?9#DfT7i2MYq1*ivA08 zbZ;Jd)%1uDe7N@zGZ}uQ$*As)E;lW1Xl+0&s9Zy>i6cZj_(%;nNgxizc{BEH6nA9K zHYd_T#$MbuQG{Rj`@++g$^_wM1)yH60=wZOZ*iTZq@;z!w-D=qK7gxBKH0v7gq;#q zW)MUWUmjt}&i%mWM2dv*ebyKhKp$>S@&G?g`~{jTU<{@25Q;gPs1Sd*V|4ARi1=BYw3L=YFPV8$rS&Lx zTl;=xSY(Qcex_7}j8D&Zv3f~P8CTR4t2@*n;)hRp=$mILTN+VXZ+7;h`)6sR*LkI! zPOr860$ox%|K4C(;!w?eqdM)5Vf@AW_n-7=D}$C05tYME2w`?qsanx2OZqYPL4KJV z@_vTgGtp{RctWxiXMrl{xbhYjT3l*wbe?6T@zfjU-qSFB&pM{*vzDvcdfnsH9!8+O zN~p^HJe_pVnYgOT-cD@}l` za4UttFp9im>FCcoSzIu{T`VG{B$f>3ccoGG!t=i$gTg*2`a2!_Bz!|RRR^v4Ef040 zoAAFuDO|MKXcLUmz?^RIXa*f?yB=JAnfVm-m5i8Uccn7l7ME)t)y=4%Dryqta$|y* z`HCg+O}CG3A?vRc*yEPjgf-J2ezQvL)}AdfVKCsoewiBeeP#bU^6RMixVY4A?fH#u z)Rn|iW-AsWWVOfA(TooONmXi29Hsj|>Qbu>VK&ih*neLyg7R<`ok{ANnXeDwnuJ@i z%`cF}k0k2f+?_>)p8`RKAGVsiXFNmw&L1o=Nt`>tgp{M<@w4pes=0v!qlKCUWNZa< zCWS!~QMSqY_B;)IA%V|8@8f0O8;BM;Fs7BSHk`gLu>UUo47MI9OHr5Gm(wGb;d-es zyz=Yy=g};3`{cd6#6?&ExX>%KVbUIyo+uIYC20)9|KS@{yuLvU(RsIodAHm$(anmg zA4M0Pz!e;FO5?v3ioMz5Sb82gsafx6A}24*C*iTM&chw?X=_6hQ_yOIK1(l6pVeITCp1WhL`Kk)tOiz%s5HTiIv5e*Fn#e<0pAChRoR-u;Xh%5Qh- zzBAvmTP~$=H$5C=|2IA~7ytHI&>GIY5JGTzT({cmP`A&6nbe7rAvSFf1PkYBL0c`EmgIKA8tO zy=JifYQy3Kz>kEj#yPYfZIBT{lTUtLL$p3Y0FVpe!zm27(bB^aTPVV`E`IY-vYbK& zpU*i7!Tj&Mg8z|u`u}3<{9nzu3D_{Pzd7D`D93w&tn9?`?v}hU=-lBSH%J&^U{U&; zJ(T|+O;~VDyOU$wWiN}4i7dLqxNDAWOrzq`AEI=^l+Gkq;O@{Dt#d(Ms{(=@gJY~g zt_mb^Y1TNwQam#@E4b~79~3vR?9Gi!C~}Z_9bxT6PieRkuHo*t)cKX+ZBB{MaCZh0 z6A*n~3cZfWG8#w9731&XL@V%mEh3s!w|{)BU3?nDY+^mt6bKe+;_tF`eAyG=;75Z& zd^$U856|t+szF5Jjq4Zq$1JPWS!~_%jd|nxMt4QM*{9L#Ub0nYw^_8z)b z+m9^2;8me&!Jby8TK>D$eTKJv;z_bqGx-tg?Bkfqp!R1LuNDDey*)VYvfo`y=a!^A zYs;{c_~Kz{5y=HPQ5`!}f`D&T714a6DC)790sgY*QhS#m{}MQqAY^10-X?&R$jrAY zS`Z&q6%tI+en$eQYuBHgOj9*G`iUpj(Z z^Yg^8e<&x6uJ@$TlrP7qbS^Nov{hYGLZ#Z~Z!y|aw<2}Ua~)Ji#8fw3O`a`*B#s$( zELP&8eO!97f&i^b06lJqK%0frw4M0SiX;ryja3~>m9K@L81VTxzX*9bxcz>K0+-SY zqw-o;s=~35q0D5zVoiSdJo>f-6tdq>YE!}u@Be&!yU1o=&r_6`d5F2P5C%7?yk-Fk(ZW|byV_wEVgT~Erz&t%<`TQ);#@c!ZLzpGu4N^3QlzM zVq5i$Sx%oAiH*Ay*V3x>tE6S~+gKF-iu_Pl>ZA-$*WRV`5~-HOlRsDMHHEU*vpcswA^JD7lc z_*L6eWTr&TX*Dn)W)nh-B+hfZgx)deZnjA&<(aR|+-KTl*|;p_HaXHlf%n1rEmp~A zVU~v!v6Ef%E!6>Z$r_e%DLcAYC#kr6k8c3suH=V)^Y2`%9KpIX%f2JMZx_T?m93#>GKtB=&Gh zn&GwRa$AVynJLU+Nb^Xxfso7??ylad(g{R0eQM5++)7EA)anq}n1Nk8;=Qa_iGC`n z=w~6qJ>?dUCjE3aZnYps9;8bnd9C6TIecCIC*jjU9zKIxU=S>SE=I?VW9L~WnH zS?t9(sUNw&$cfw#f*e-%oAE4rMg&{|*sj8Ou?n1|n|;NmWMBS_=`FsAJ%5CN2H(fC zvZ@r`#m*_Y(#-+NW2W@dSa`KAY*sB!x-h0^r4ReF)r_v-`(3Da= z&K|O1IL`QQ?_KD%9@@sI;l2XwnZx8oMpKo>m-|zctPifY24|&7@*$UOA=(`}{NMaE zmdzlY*BBPV>o$5?lM`J$b~P1BWNTPKvPq_7y~1HLh#07pJGf3Lx%7v3OZAx8$4^*1 z%I%2!#g}ab=P8(!A8f*1ct){%LcdL_@s)Tbr6TKyq4Lz7pRAQ>UwsOH1}+iT`Y+oN zZz4hiL?->*vmx}GGg9Bmo!_T(-G0ZNNHZce^TE?&E3;KZGiQXag!ev(FB&8TqA>mg z4Z%nMUQFZurkFl%pK&9oS4On&040nny7Ed?b~dG>4o%&)vEXu${68BztHv2Nc?XRz zeel;8B{{cfzbP@?|CjJ~$loP}Obj2Tw-W0_>C|+*{LD93T1v%W`NQ#MB=oK& z;y7?&p>tNbaV*;_CljQbx=9y7xY`Rl#pQNovQ9u5U%Xg`(WxApnAn;5wf+D=eOnfN zC_v{~&w8-Wcgv7wVXHT!OvvfwfY7AInemCM+J*QvvBV~x4|}G7Kk08uC*m!jdVE}W zsp7}>RFl<}&GrQaiYmxG<$xUI`igC!-(&bn%g!?vW*31Ym4l~=B=(@rK)vJOx>szc zu^HI!=CoMn;-wfLFs;4pHM?MbuD~}hUj&s0fg9J0NZYEvA?zzDOlQ{3KQ>i0vE5hD zVE##+%=trQ+3^55L>AleT?~c3b*4ICRM9H$e|Zz}_<4$dSJO|5VKj1!@yOxL&9zG= z$`uQhF16$7n)k<#R6bjE5^h2c$N`GmCvO-o%>t(k)c~sAs3ANVQ07Kd)&ly3yZ~0j z==wPhg4cs!Mqo6sjROK6OyDa$w;e$IxI}=h0`wx<;9%H~?6`RdK^0d+po_bV7`}1v z3q%AEt(F0`#%rtY#lt@ibEZkSrh-PD%Oe(nnz~0DP;+o%RtQgG4+(=Dp8Ns@ko^KNsNlupy5dg# z0P8p6U!cg`Kh79}C6^K-M3SF>1Axf5C>WXvd*}RuFbu=4Nw^vJ4~O|*&O+Q#mIQzc z@BqE#ctkhH($Fa{=T8-&&XE`R$G83WM`;@c9_R@;fWe}f^>Yb<)kSov;-!9p3Wv@x zFkA_2!f%ogn6*N<`{(5TPbOF4n;+2%weREL2el&=oQWR2Cr`ar?#{mp{{%t=l3*?D z@h)w3-`cKN7|p}>g!Cy50|~e8@B@=gq=TU7Y&p+I5>dB&vA?*}o$Xh=#%Fz2vD^<)ES>iuHF)wmhI3V!l^!Bd#Xo4nlVC zR4A+pIuwFa;p`WAr!TuD6|L(nZp>}Vp8DXcj!#P~LwWIcwUNT2H@bDFmiXwuwI^lR zgVpfhQ^C{#p>&;)Fknt?esFdh@#Q&Y@w^SO!8$gaiP|!|qOJerx4&YLXg^)UBa#&# zn*icr3)G2LZww!APL04H*!f>wVE?1OR|bmKTRS6feY8lxM*9=N6MnTsr{lkI5x-Dj zCePadNZ5LOuWrer8lX(Y4^bm#_XsH(=4XF|zC#!SM$>wLWhQ{r?+#AUMZEb@1j9O> zJCkdiZDwYK8loh*at+aH@cc}knK5gEO86x>ntt6mx z%Roi>qLGmrRUSa4Eb#${`N7ce+k%(7uGv&16yD7eni;&(5F$3|^ddwXM*%wFJiawr z=dX$W85tnzSl|0~Ww{|-7_a04EG=bWn(0pZ;i&fAl?C#p(#S98frAC@RXjoI_YKpv zuby_)Uta$zhOnDId8&cjnU9%TXXD?&3GVE`S8D4bEQ1)x6LLb7l$a<=q(C$vhV*Ql zuL7nbiS!lPUvgGuRM68~vi^BKl5X$mPPJ5L$?h|O=h9r61%dKRn4jB8STSH0Y29H_ z7A(ks(}40yC0pvOx#**wfIj_4S=m2)H0F;8$%Q6HrkjbED%L`; z#HvRq%&_ZgQGR5#seaJ|3Xt+DT(&lsz!hR1Khlg&OYOD-$BH)vborvKK5$9V3up33 zrkqXLx}-L)iaPl3Kq~rlmbc}(>H>i_XXX4?r0oH zfj`7qp56A!L4-nB+dzKzM`P2`LsxLYTJ6Jiyx)Vg1zR@^UUh4K9t>Sj)t&03G*q;(MwtgXW9&~-j32k;&Z3-bcuN^-!(+2|E>_F$ z@^8;{U^PR}=lE0O7=A4|?NQ_52Y6371l=*jd8J`=y=OP<`!I!ekDjelq7dc(Hu5 zzDhOW$fNVyGy5KQ1rM>a;dqowGO=oZnI>h*VWrt9%*G-*;Og+`r%ZC-(N$qDPu&o= zeLSIKpK|BU#PQTjl~R$2k=6}Nh%Oui@8#dHcn!G(Wy7d^N`Zm>z*G^1(~JrE8Th`a zh&A|#hWJ~SJh!nWkO+tZ1cC^82_IWcK#k6*?Ja65yNe#Zs)!;}zM;A<>6tJu*VB>` zGR>ywB*1W@W597}CbnF;laC&vMlEF+EcKgnVr|}AJc~06Gp>zOYq9I?X-Q@+`;y6= zBWo1vvHh8N7jVuvNU}IjM*3$HdfRE`uh~~*^5c?LW*a8lrL7V;BDZv!TSATQYd-&0 zlB2>-^t2^hFwg|>FQyPPA_xLA2QJWW^!a97nXZkL-$$SE&%tSiEH3*RE)ZDa}ZHqyP@u}cOMW7>bLX8*D! z{qOcKOkwMD4_hRND-Epr+jZ8M$ zL~)NP?AvZ&`W-$h(sr87a&){xvBZi6c{?S`-G$s!BDuP$Lp~wF!^I1_yw#(w!0wBg zTxL(ka&|?OO;t|sevsFjFNG|a49XOLCSx00N!TT457Aa3p%X)DmxzZ6=z6lTU!0P=)!~0pO$o%ol>ZOAkN@w+yjd*U&!+}?pTrpR zWdZu=>2t*Cn1AJY*5ofxx%Sgt)12b-zkc_deERnv8w&k7`r9=9IS>Ci*Mo`ko34>k ziA9Jf&@2Hc7d6UXxgax7QDrHv1;y-MQEntK`c>9uO zs0q{1EI^C#IlU0y`Ok*u{5#(d`18=efx9ZL&Wm`av5VbX4N_-}h*P&vt7EgMQfYp4HqF#$%u{yF;l?EE;g8M6 z|3B-)KqJteSq$4RZkr?wZ2{8Fk`eizg3-^??m5|9(biS{uas)_pPWxk*Zdg#!1p&o z1QGH0CBC!qOT5HK2gioMP9KbpI|KZAMy9uZ@SXhpH$$Oz07S;|cf64QHEYJIUm2@Krd0XZuY$lGNJ`@T2y;qc7Nfldr|Mnj>QrJJ6VEtbMJbusNAo}|> ztct-&^j@?ue5JWz^eu{)DnBpg64{3?5m-Lx#Tx@pfa*5XyLbpdv7Z4z3i}e#S%Ymj zCr0dx!|-N|#IJK&+Hv{;k^s{0LQoF-1&XS0G#EZIBV97yoY-;Ur2a%t&N;@w1sM#y zZTAnA(7y+d{r6T)w-R9~A?LS_E)Jch;9(h5bhnKFiS_=r&p{7tTYquxT*El0Mx5_F za`r5%IQL&h0{?Rd3gpuGQi6HA3ZZ&4yu^0~&WF-t$NBy^ah+eFRN;dy6Wv+*e>~6l zukBCk3G177XABKLVUP8TvMK(H3{Y)YUj3xTEbA7;8(+mw&nlML7Tl`o3;5~};Se%m z1ar$@pjQY!`-t5K0_E6)3#hRq^<#dQ-GG8}ZB-kKDieg;k+}cwA5*EW*2Vv%0p;p? z6mZRmOwR(RBjNtrats>ul?6_-5byB1-UGOxG;tGsza#w}XTsBqh|Xxtge; zu^LDG-~_s726#vFNPt?)4(P7$LhwQDD=L5c-%REN-j+uJK;$Rn#(`z7@R;c=M!9hNdp3}GDj2K3vKr8uP?>&BdjB5Czb^vAv_hR=i(DB+Y zP~LNcaFhZa-&=0F)nv%;HchIseV2ztohWFY@DO3aA4r~FV z!`~MFRhrn-&x_?QyBfeeyj0(;-c7#%xh>M+E&AdBq=k0I3 zM8=o%^6Pr-!H;Up4osz#Am-~+?(*Y546?w9Y;gEag;lDizLMu1+OoVC$Usdd=}$LG z@X`~xqwe8O%XRuqZJAQ|W9eITu-ipPP&YHd@xgcrW<~WJ=K~Yj@&e(E`Ohn`iFnrf zV$6YV&6u-bc|n7n_Gd-zZo4&^iX~N!l}ZNGW}4Yxg4?l4LCpIir{1j_OJ~KLb-pf< z72>s%yA#W1*R3zQ3c&E+p-fiKL( za(*Oi$y@p>&-5e*Qpz$2nVdC}z9zmtoNs2V!Ks%iciYgdsqnLw%H4#_);L8I3rvK4 z`=KZh@Ci6>b$^pci74EhJT||bx$oO(rmNhc>~ zBc7?|(AEaR=BY$~hOZNg6RjI(yfOA)G466_TjnL}4^Ir^gjy5#I8a|D#|z9H^_L~~ zJ-;3#8ZD)rYPCpQIFVjj8Pe{WcG;ZY`NrdyoS)e0U$4u#r5)W$>Jpt*DeLfQm_dYD z(kZ&EepD0UB1?Jpi97u}2XP>&9dW;axKssHwrHz?=F72dEU%slz3RFE_?vgG=`eb9 zN4(|is<-7B$AUVIzMibLxh!$CK@FdU5l-6)%Hny&KtDCptiQWA;q!O7efXScU_S_D zb9klseVd#a_<^H_@|6}~0kn7H;*f`|c5sqWq98Gh#OpG*26s4XV_o~zc;-g!1OK72 z|9$Z@Koa`1_D!L801xA=Qxyp>3E!dZFTjf0)rB|)_R>vi&rW`y4sQg?=|ry8y0Ca@cHeo{b$|RxYoo4^ zj$|L4PS*uq2jdnUDbLpaD!NyEjx|{S&#Ol{3sUdv@GJqf5@Ynu4F(bjWeW)C+ zFN|+OWEsyCbO%N9=85D)uB_sMmkcv=MwYhAUVdU6=PNUCU7-&rLqkDC8<}+@CY#3YbD4VOV~^#<>evidCPBj&XZYhM@SbQ3n#CAlgVuea z=%;2ux2$EE;=!MzWr7!)Vt7^w)!+D-TR1_c)X}= z0Ae`melE#oq59U;*wi{NkYR9w&+7?TOXWuGZ)eVXp?nYT3q#{KAt&Bpgp2qR$3@&R zqU&S~wtoP|Q=UA&_blX!w(4IJ7GAVts-PEv2ndES0tt#BF|u)*nNeyIH6XOf|M}9V zL`Eap1j0xn?}Z)Ufpd{T|MYZJqb6Oe{moq$=loTVA0@~{2Sc9FP4Zp%9P}~oOUvO> zsv!BCK<>YMcHfbj%Z@HoGcy|E8ZQKQ#w0&>zb3U!t{TIJXc?aK66fbM3DbG?sSdw1 zDYxW~{ka{5?733h`i8DCILtSKyOByPG%4@qhR`(Vg2lAf#A*jkEpT zl>lhJwjus;A%LU*&i(KnLvrJ`p1D{Dq7YgjAL}-kS*~sJBP_0{xCNFICdT z2GS#r02uXCd$Ov`m>WPZ`~3>NJ5j;)+5d|6!}!16^1ofj|7>5xe-~J^2iTZy-C^e& zD+ucJ=JZz6H+);n#755W$sosTPis=ZPY*#qKc{&4qgUtWjt3$n3?04lZ-_42HKXv? zU(B8dA;cYMW}yZ14PUk2TS*Q1l-hHdGmU&0dq^o%>NB+FUD{}ZV!0w%i!uGkVa@uq ztiGxg(a8W54)Cmgnc#{&(FXYbn-%Fnv6-4@5q0J4gPXTU)C)o*(JDeW?5`=s)2w{w z$n2&%$|Ex<#|3MDTl1ISKUP1{X2=ktW1o4Bx~TUenMs-o%sJ8&cUg_DdQ_*wV`C)3 znM1Kpd4#rFS@U_>d-g_&55@B)rglC7uN-AIlX4OmQ)10bzoKHk(oj5sA9d`cbxfLZ zgrbxU=p|mmzb8vuNGc0_1^eex_;+N}ctr9R{Fe4arjE}0s9xD%=CGocIiB#rideJp zASr}|>WTYS+Ognm6JS@whx017sk2`RPbw@kx01DbDpn}q{|fcE$EzZ$WXfLI$hmf^ z?$RS@u9##uXNA`D=|c$@0)5okfOD7bxbw#7B0y_!`N1b&_VSy# zPR=f~J$xxugIM~PM{j#Szo=K%U5b6jK|F&j?A|XZ_qILuw~>fgJ)gX~Xmcr1a{c<< zFFcv!k1VcOm^l7C?TzESmzt!y#(JSFwtL52`tc;5ub`pK*n#lyKt>EbDQpU_tZb)n^-rI}YS6>eG>LJ0Ly&Ge>< zO6d2ml*tECvX@1jDju_e7*Y#x^@4Z0w(>IMDW{eC`ZY$p!-;uWse)T#+mf@EV|;{Z z&5TWZoCT3lhS}EIuc_V*b__CRUIh8T!e6$^!^M(me50CA!@vmf=%sP5K#a>{l~bq(jdX)Ro*aLd9knhM$Oh-WJ^@`)MaZ z{k(9={FEC-xQI9w2W84u*Tm_YnW#TGmMQVZek7ru?hYnPIG|doe__(#vlw(^RG>CW z-LYIru$rKKgK6#EX-h&X&qw0yWx&f)3p1B9w;^Ml^8F4K!Kqha6BfqAG~_dmU|;-1 zVdo*4rn=Egem9AIcbcF}R9A?~%_8bg1LE!B!`E;>@=@rh{24EWT!>aCt(HgzURLA|6?lk3aaX{Z9Y? zTj9X(a)5uIc;K%MB26vRU!Y=_u9M;37@2<&51dq@(uB$j{S-$e5{k^`<~I3#I8D3- zclv4XS8c~o_gWDo1vCXSK@tO-u8u&0$=e_KYvWX%EUh7xFGqQq9&Wo^2&()H-uIea zXysWJGgooFIkDI^YOJhU6M8z~7?s=3Odfgi>?zrt#e;psHsWf=b7d$`c2rV<#L`De zj%T7$8nd3O8nGUGy;8lKpr4f&G>Xzo^TuzsKK#9ChvIZ^td58GLBqNwGpZ4+>G+CziX z)ILh({XUMSq`px53=bYtF6$7g+#qJR9#s3oVKHeuIs0LinQ!PwPo92PzS@tRFQR#5Wi5tTM zslIkhUz*;Dlw&s{2zy-9lChRx zbw8AGZrdoFl>&4S2UfSrtxxduMxO^9Z>dz7@VeR5a}n_2>0b<9bVx&~416&&_Lbsi zQM2l2QRVDv%n)j3aI&b9dzwoA*6rC^2yGaMGGR8W+pJRxK`0$)vf zPR~Wx$5q{XTS_=YpCgEwz#OAT)-PoIihkN6VWlLL0OH;G_kyY=BrJL1uz zzxIFuUB>UdOueXIAR&wOiTdIyj-1F_RQz8E{B~*L5b)9LTPMMlcTc!vx?jDTlm5&+ z;M3zh*;9GK131tC?ZfTPKpASX``2f9m87ZSc;XT3O6q3nUl|RxSPpAK zVjiX2o$A$A(wmz1|8P#bt;m!j;UuI?e8*ylJvgu8{OZ6ZPIsggXC*H`%J0(hJouA2 zy9KFN@7l}KbLM=_h0=?eHxu4*hp&960z10`0SONl>H56*4Y9OUA`ZsPUKM3)E=O+H znORax;$6$gZe#;sObzPiH62{8=5TqIx@bg5%V3``m(<{qR>+m))mu+}-Ip5$?@^Wx zUGP)Dz8sb-Z$ozM^33I_1v9Mv)NNaNR`Y{o2J!y9KzgQHGF z+E<7hMbFBlID*qah)AeXw&OKOh(whodm-Qv?|Z^O1*f;rDI$msVt#;n`f@-atPebN$J%=d=(hWVn0fW|#o++WGVw5P%l8tId( zE|3V9-)bS-Fnji)Xx58oS#P(cGKn;~!dQ{sjP~IRO(M=dSF*mQM|Yt>XJ7K=;x$Ko zi^Q_^W zVwtwLvT82JPd&@5EAV$c9MU@EM~u<}p!o1*k0>e+kaN z#9>mVJ^V03UEk~}u*;zoY6tDe;YEazi};Z3j@V6Byd! z-mm{W_W`_nk}6~;3k}}mt`bHyQw~10KQ+4z=cZ(6sib#7C&vawY914(Ovk9BF@(Qp1c??`dUR{W}1?( zORh3OVjJe3%j4gKpjP>~O~URPRJwShbIN>rK;Yi3`=R#_uH7J4A!CA)vaT>#-HYnH z)*gMhis`a&EG_g-Quh_y-Zz=4pW}-YbNxK@{t4ZyA?OmZg*p}>G5BdpoHvBNl=UF= zx1=rD@7}ZyKY@qnf~=d&HElj`rS-LpxkG6EEJg(PcBp(L-nNHMsfw;^P+2}pB`d*q z=pHU5n87*~NE6CwWwroF^OVg9%ZPuoNQRiC2Eby4$UtaIkBFC|(qzTq=O>u_90gtS zik&Cu|GcLo5I9IgD^=uZs#aK+jIRTnCxa`%Yyu^!a#mgVT|sUALz%A&v3=4&_NJ)afLs1% zJ@#FfVPb7C5B4DU`oA(ZCj2=c&o3DUnVTC~riTNWLEJtG%H> zD`(qh3@BEI$+oh#8-TDjo-Ww&*)LFj(&R7$pjrRNvESKb|BMZ{|K0aQbV7Efh4|u$ zg`GD6vSfy3(aDB@G046d9=J4}ElyP~dPTnkCH*VRlbdz^5{40818gZ?+*AZ$c548N z{BJLm`>h%GKl_6GZ4eH{HV1YuO0fKYu=n0^O>Ozwcn}bzDpf!_2vS9=v{0l=Qz_Dw z4gxB@20@CnPz0nmY0{+k-a$aRfV9wiLJg3_cYEfZxo6Hhzqxbg&i&23pZEL`LUwk^ zT6?XvzvcNp&q{UF50F5|l>(2P*Py+GM-YRR%}kOx3>8QC>E5N?N~vV%tBgxn#R2MR z+4duO;mNN@4#VaiD^VPeyq0rx#7>8ttF+BTED$8sJPvfm_d;+)zB8M7?Q;h}ZcPaT zQnLT1ocj;G|7Dr^;9KMZ_QEmOFu-PTqpyKdQvis}(Z!Ii*<{2pNq=6St-MQiiRaRN)%`L%rv-i*S*T#` z1)na(bl`jBrPQ9bMBA>*PuknjqI# zOc@rd%tIofL#(v?0~F+%W?Wrj^>uOBZBJ#@lUY57kw>A1XeAw7;`UzaDoO2fBw?3< zkC#cAO{JmS0OC`nQhD_C+@}QbOk`rhF&}*-;K3mUy+yXCJbcSUtg%nmQ}dPsYlqyh znU-LU27iv3{(q)SI6--m+I>&@-h`z_L@Zr|`BGpFBFE+G5TZe@yjRB_gxP0^#A6l5p)&fF3{9naJ@U@L)P577qj2u_$J-YJCz1 z-Nk*z5nNTUFC3n$xLAry4Hjs>#`s?3!l$}b0rYYzgIE&V+MYOjlj>2Zww6$|;{KfC zy)TL?QvEvy$^379q?Wh%7nLg2o=k+%JeR>SW!c5j^2xk0jU6}SQl*6_THqny>6I6W z7qY*r_05pdCR=XQ^F@YBmRzoK|0-=8bXo6Btp1ue4aea(@#1Mcvb?obGAQ$7=qr;D z1(1w`Lu6l*0LSbV&*$nn9&*mL?nc(BPmcdIaVec3D>Hxxu%Yz>H2CG`0`(ZsVehTP zFb)GSi^LC*CDVaqav=b(EC1(syLtDm%xhX=c&w~qtj*G4zZjQtSU5MLZOeOaDYL$l zgC>3;0kJ;?DAC*{3*&gS|Pm!b@29726C0kw=BBHwCEQPfSp?BYd+;OqpKr2%B zPfA04su(KQGD)Yw zzXNM>ZvZuxzr%0-6Jqv?mO4DWpw}v!xFBB2LHNT1!)o(ks?go(4 z{7}GRz4ikXCjiVTkjsRgAi59+2AE-1zd)9i{`mTjZuw(4{4ovw|6d){eeDh3JWMp; zE;cWWvWW5j0dgS#0aWw}qEoYx6~?n7$VE6)R3_A*_OBX@zZ#K@(U599R3d~N0G|P> z&+R6x^xp1&1r>M=e6jiS+4Pa#?mobsEB`Zmp~JMJM`i)=z2*H{K=$`q^Z%Rn!}{?X z{`5aTlmDxgUH?hO;D8OZnjhnEegPk3qIMazX|9+?skc|NxQHfZbg01qk0|?lgHLo! zYvv%3V?Kh|-@n$@6OK_{}+>fpUw{(>bRDOtAm|v@L{x33z#AY}C$16gtB}4=qtR4fR1T zx)Y|ty~Cah7kp~{(|xk}w>BzUe&QYzNqiT(9S)n9jze_ikXmG8G&!is?KmqCvJZPPuhIhRm1J#C}mL_qnJp&kfg zEMD+TtN*7LYw(_uGZBQLNh9hT>#i{rb>6;b!brLH%RItRU_JkL5X_{CBeN%q<%^(U z52@@3*^`1|C5%;uZR7M z-v2ww^Cf|*Yf4F)rMbc;@F#oS2De7u_ldgE^W~B3ZD#%w4vOs4bl8rkt9oEKP!Ag9 zuixk;uzK ze#>Wv4)W=BcTK9Otcka4b4>>6$p#XGH$RpG1iH-!9y#q$H`gZ&&NrWn*FvltwVl#z zpvLAwY;Kh2b8vnb$6h{SdRaFFVW=>PBF&rG30UfNc$K$J%;K94Q**A%9liCT|K_g! zu?l9zm)K9suRFoC`r~3HX`ltt@)PpjTxYH@X?gFbnQgL#vJ2ndr1d89V(WX3+|?dN z)*Ql{jQGCZaQ79)E@L&Ad#E%n%5KbMj*)tE)SXpTy54OBBi=~j8>`{&Q@@D0n37$92T7(jwhPvPm~-QXKw z>mg?tB-FJ5Zg@l)+!aN%nqfhST|+jZ%h zMJTEgY%CJQR%_}!+U(zc5W#<6J5r5-U-g%6M}&m>vCp6$z(o?5E{z#BIvN^HATQM2 zUq3n_6ASEkkwb)&bf5pQ_2zK@HHm5+) z&$H!ld-F>oUwcGE?&mrj5>D&`ZeBHwiQ=4zs+|G=gJIk+q)|r4xlgZx zk`FQL>FfAD=a0lnEPa|A6kA;$=xqQL#~yJqjG2C7h}K}~TONtr((Tz>0`DBH z4;PHX^f}L2blv)yKv+AbX&Kj>o*_6+KO&?9mzo(3YmwmPek*lNmCEVS;BuI=HOpsn zi`WjtOkiJRs$|`KmA{*NMkQ%?qZN6V{xb85$B>6oFMlYwDq~L&^2z5qytO@CivBqC#R*-Zu>IvzS3~8}q?VCa zHXZsoH5q3P5rP#fsn!(0ucPoWzcli|>yoB}Qw1RiJ6kvqiD8bq62@G_SSvOqvS{?) zAi4yV;-SY@{zxD7>DsV#19JIO4RpyO1w&<=*imm;A0|+|&}+?R5&zswr^Pbd+h2KG zaZH9)7~vjJ+QNky@*_tuLd*Pc7wi(@GwP61WH=x)8F^adikqsabWde1fipCNN87)N z=#Hc27=)_jj>l^!{|37;^{zt4#duYxAL38_YX{U(1*1;gTpv}hKGd8 zSsHX{ivhG}d#{$jR|jniJ;0r3v!(Uy8}Ige@?jjc%~4W{kMGt6nI(v6 z?<*rmrv>%4Grlq5nnbxS^Ky5$P>yaSdqoNqT~0(+>QHN(V#Tm4(298 zseKXG9z$3K)g0v)3cp=l9kOqz$f9$IhknhJb!OoH){k;);X2|hLYirI$Djl~5|KW+ zUfI-e^rA$1Ac(@CyUO!fWkSDWo7pQFh8&}j2*|2YBcSsIxe&0=E4A(cAMzOk!5T37 zW);@>PwQaXC6ZR`M^6if}Xl4Y|;?esPiZX{f;YMX&`i80}0m2q58|pDsxJ z0L8F&flo<*Gmi3_-u4^H!1p1{^`U`JckMk^QFrRT((Q_0#wW-&>dEC3YQ~1y)24ia z+oPcZNQyq&mS%^q$GB1^lzf_fYGec{3iDivTtrVkzlP$rXD#uwMKREV!zJ-s?jlCo z_cUQw>tXrn+h=+S^wMkWi>zF^l}1MIn4{RSD4*~VAm(Uk0shPz$Bb{LT1ifj!u-Tr zvx||uE`%zMYmdG0LYzJ>d^+r9OU<0WCIRh#Gv+T1RH6a2wN8-(Gj^x$SNq7tqF|zj zGTRoN^mS+5uhY4wP_OJ^rucIniuCt36ejZD+r`dnJaYACvY8!~2km-t1n;%sd_F%q z4L~x(D?3fEG^rJMJeIG5&!0x-4VX1nM4F|=IZg*Z)mu-pdZhg}sKOBJafNdSa!89# zg3LRig-bxbF`w*dHQw1dRTq5|x-@%fSr_wM##i+ImHdj9@`;kzGmW~a?FHHQu^c23 zQb{UTTU6j1!9x5IjPw}hMU+BCxIs1iNsWP3e7*@&!qmJ~$Z)bV_8P5y$&@+;qoP$eyxM`XSd{(=$trQ>$(JX^2J9;7kkg?3Q~Xsf&=hy!LojtbF|! zs%gIRE07r@&SQXL_u_d)wS%|(S0=+WckP<-XU;+1NwJh1U#Xd_s_j=Yf?KY`r+XMf zGssZZ2yXSjE^-^Mz21=H9W~?>Y+-n8h@6+=o}7aD2J>F=S4}k&iElwx=>?O^Nz!xsxx(4!}YcaXQKQZ|?;>+Ia05=%A0LNBxPk{@-;DP(84cGMyHyreVD z$qX|l`oQth6yWfjIyjPsG}qRMAY>R7hCFQ@*Z|)=Msl^-ZkM7Sn~hUSLy9XZt!z`g zEvYI}b@tehtm4CM6`u<6;8~6Fld@r3r-PPzNYYd1l%7g8p@y15S0_)FMkV$yZi76$ z^%KG93#FrIS!U?N=^T^+kSbFrU%~6xCFePi$T{ZCU3buBY zoeg3gd24>o5$X3lO1+mjI-nrrhz_#6)MG@kW;$0|WZHox>O#0K48JS%%X5``1^b5U zu2`WuH0KH+-;_d+5Sh`;;0^tWz2aweOb?E}#Bj%bz4IJv*ju-uq9H_%;By~qv@B5i zX?5^69UGw(gaY&@)cN?ym9lpl(nIni)%~VVrNoD2Sb`Ua=GQ<^-`xowzJIRA;GO3Y z*d=0G=@z#Hpl$1_0<{sfC>HPwJ!#*X6!y8mcY-l*8T2KWHSj*;ZANCiYZ5J3?9a8m zsLq|-1^eOWN3K1Dcv6OwcIie;Pw5`9H+OfvQe&z7Bp77%WGxgg7SDOMX71So#V-&gRVTr4W^A+zqt!`_UeG#{fSA0!2lS2ia zXRKM|=G?XRCAhr-Ab+eBD9H=&Jq<(Z6?$N+)xs~3@9k#Ya&aTnoN&Jg7`)3~yk&NK zHQKR{M$!UdYX0>f!dd(S7!5qZT!6!-w-hp0iwPGV*Za$le-rkBx3aOP1Qft-bTj_K zD4?YmtYorrsSWV)dm@y6LU$-Amt&?vgAD;K)`F>z^fuQo{zabTKP{C1AN+pskKfWF z-$C>oDVHmXNd!O!lw5xmAa)ns_;js)Z( z3CNc=LR!cn_7DJnXcnGzy2!fQ;xy}M3B+`D*41jAQfd!US0t^mXA3e(Ng9xM*^row zTMn+4Q4&y++K_5u-o2)-hEOBA&^5B8t37h6(dK4@JqjNCiI<`%OQduDcO?H3q}u}} zyi}i`V5r88rsY-LP<{HnpG`NeYBU(?Ez%uNXC|e8WNJGq!$^$MLTbY`mqK>ST$fsD zXY37ngG%_a8(JrJ`x14-E?`UdCzI9tbXML6TWQVdt<4Tb``MvC0$`=HC6la=_TXEN zetdSc4YHQY4kR=}C-y~iNn~P{F)yB|xgi4dg-XgbZbmMv`!#6dh~DjYaHbuk_@q7B zW@-5>0AKRDlD3KO@<`y~HA%*zG)RZZwNW8;?aGuQUXj^Z$Okjbq1a?Sz2~~W7_r*Y zi{z2W782yTgPB1;ymV3PUC9Fmvu5$2u$hd7^YArKZ+G9``SGAclcqTQM;WmObAe6eG3 z54@LwRLZoGo?b;~49~OnXK?$Z_?-$g9hVto`%9WG;dL+~wKIr{TYySOdx!%%cKu>w z&qQga*0*9^EwaTliBH5c#kn!n8e6O^!$*GUVAk*~!5T z=DF8g_@P3Er&D@u@#p|#7Ga%y`6 P+yv-I<;>Wy_Cb8&fX7rV^4X~`Q0~JD${TO-YVZ~ zO|Z=3H4pM`X$HVCk~Azr4xAZ{H7QP&n19ryEophrBv;C8rs8xrHJv(N0y<=p18C8F zLH1%423s$!e}HnR8tm46%zuDb))vu~fNK*jLoWh(R`Xk#tLF#COK8pxX%Xi##g@hw)aXOOb@Rj9^ zj&C{zR}7P+2eQ5MB12y_E!`z* zi{{>b3=dm*3??|?ZkFG5MoC4`Fda6HR7n`{HuAxDDs5?o>7)b}8quuF8J$ql?Too( z(jcJ{QEj%2syY33q8V1av(Pv7Ba+ijG7O}!#kU4W$OXtdQ$m!oB!8LRbtR{QUg3hK ziU~3jX4~hBbUdLXqbxOUh^YEj_}Mb=MsSmQp^q%0v(r3$R@)% zncNy?r=)k!^&{ZU8MeT*>0BD=gdm?lh=oi;AhY1v#hELwPBS?AjwH8MQ_v>oA}fB< zh+)A!6VFVw<+7QS4mi@OOEmGK_p}?6<4aLvVB9t5v-O}j>a*vZ+qwUhF2~h3?Y(19 zwD3ku;o}hE){SYvIc}!{uyj3lW*6H5WnWuAp~)s!cwDyt(s83p+R)BT&rR-h0A`c; zd^n8l9W2gifhiiTJR*EdPl2`UM}?%zov~@*u0gD4Vt6K-T(0bh#&*@f^v47#wB^aj zSfbcDtge}9IH#INGUE90=7#|CWF{QlcnoAW&>t9gzX48aP~!Y0cosF3bcit(9hl!U zeXK3Rz*^`-Hku9z5%BO@wH0^jYz!2l>fje0(PZnm-f}YgeVV9AUkdw#waxID- zBMMiFXsz-C=tS@xhUR-?R?jnRFP}(j%wJ9q&P_`gO5GKoE&$GJ3R?u!bKviN6yf~P zAD}9~A>fF|cIu~29FSQ^6>k^gj%Zn8C0)yo<5sVM^i3ZC+8^YY&SkpCxW|Z8sYc5K zJ@$C@oY9fXC!^)^)B%7F@Hw9;cm+{ltpSfW3?0BjI)1W43hd9n*KBvGH@|u=tv6>R z8XtMkXeH3d3ZAFz+=5iL1hf)Wj|7{rPOwclxTb0BJW=~#ekn9nsVSO9_rP5xD6d|`v@w2=N1+oLUIMa11@swBJ9MD6MGP4317sJ zEz%wJ3qiT{cz^q)NTei}bUQOX%J z-+KJCG`apSKK)Hfhd)Slf0F|H2^_-uF^UodSQ~_XnqopiW#0Ys9`5705QaV_-3 zL3ghEB0}V>Qh~PO*&{_A#zqr=TA0gU>}Cp`XGKh+VmUs9vppyj`+kK_(RcI8stGtu zU3{!pZ;W|jc2u=EuHH%l$`S2_PzT1)v>bq_F&IPvaWq@VGA}$4P4MyuXh|M|pn!B3 zF7sbdECXKwGZA(NE2a!NqBm7d)e`oU=l!R$M2cbx2YPSUk|8gccUed>#q>R)G2yOr zYxWPzDfOk!CR0_$k8b9S9b1gk-%PNGZds1{z{TyY2T)Es0acFE-MyH%6IdHU+6s4n zHd#c-LA+Nx4c0QjIzFn$ysB%~Di|>pyqy%l5}LvOVToWxXmD!W zmC*Y{;r(1gOE0L%?3n3d+QXr0Q<`OK-1gqbghY3$GyLm;l|yFT`1JTvjYN;kbn4)K zA@-69wG3>vD$kxr<#F^`im}3l2Y19>qtb+4eY3l<&9xIdTEzJ{J;c@ZuEAC^JWVG&n~VE_ z52w3pvfMH?UpuUNQsS?%5_VjsZXEXtpyQTo>f=n4Ar~7qK)f?cnETCu>DKhDQOBaz zo6MMaqpLRuYMG{5gIus-^x6)&&cq*O`d{(M+~{hGi)-V^9GT8_U-OZG4beyn=NV~A z=bA;G#u~9?S(-d#3he8Bc-(75u#VzP2$Y*%on)`0`b_8xZ(AlxNsV&H{tEMFge+Zi z(0?fGAT42gCPd8JL)e>6;M&*ui+kG1}51oLw!e;1u$ z59|mp?U#~q+VHbeXPNv*74=7pR%R)FBc~Zrc+E~3A>-k)ey$~gyWOaAj`TUv6$$4` znqIL_=^W!OZ!5;C9ax7MXVbmK(k4Gpylj3#l7GALjwEwo#+B~e^Qi^9#iUx#!AhsZ zTDk`7+3+_5olARn4fKudXlD)j3j&^NGOrHPIW3roU%*P$mZXFo4}`wCb|st++-LLf z8(sYVV0O3tHKfpgo|4+PQ!`KHj2K(Njx#&pXO+m6f58jqC$K$z{!U0PNajRN zwFP*A&_U>U@M?gEDQ2SPf8?yX?Zt(wW-SGEr<4!|ZXo`lE-MFf(EE*}HIY@a^|vjwIb{U&~Z4oxM2AU9Bms(|b9&^7x%kO9n7VR;a&a+4+MV=9(r zDPebF&^~L0Y2(fBe);*U;53gW+0-rxG1vZj_gdeTZ-Y#CpY_XO%X3W6uY?fB_y5^{(dWC52Ld_ z#|Pd>qx<>CbjkyY@$CfQCaV#UiY6|A+a937cWFI;x&{8z-cKMMkMkh4=XxnG>VAOI zUHlT@3D6#L9-UlVhkYE-%6;sr7f5xznd8cs2i}4!?dhYS}g?&qF zHRkz}A@=~guyG{$r$6;CdsQ-ir!*+;J;S{c4J5$=ezj0Ze=8dEJO9=cx^~xN8}l+N z;`M`X&!S(3y;RD5oveon0#HypRgjD8r718`R8(@tC1A8|R%a5EBA-$(9^;LJ;Xs%g z;X)dEwkty`@d}_NJ>_<<=#tp0HfHVy z2a)VGQzwMaa<*deOWD;&UeL_h$0XceO<%94x9%b>QKE2oW^KJj=InqUTH`Iy-&c$_ zK?oD;o?_U!5(WFY0w?gEw=w$JOZ!Xlb!-nR!qsaETn5$V-j%V1R(BZ=f33gC6!^3i zo(%A{$eqUj0Qm#ZgYf*V7M}4JKB82S&Uv}0!k34bOSC?bKo5yC@-bwYXS8+GpaQjs zvXQYhHJ;hVT&thddstOo7re(p>_F97RjQ$(vfeb@IHcB{>~I#mHd<0O@i~5<%=G&Y zP!Y4@{r+JH!O|x7rY4oGm+Nq=tI&mId}nQ9Vv5$?`yHI?cRO!xN+}5^eVlF2-M+qP z>!p~Us2$77`k3c+TPcV~woh!!Xt;g_OuXIjae8n0r0(9{`C8KG@FaG0h)s_`w{{gm zDY#@mtB!&0on*f5_sRi)A-oS~g>@nNR?vQ$yLo|H-ovE2cV8^^)(5R`-rO(tuT#I+i-I z3(kKz>YIQ1t&*{89DCeHa=e!^Knb?&m=uA2Powxf_5BLeZUOOFW40yh2EwK)@IUqWrzF)a$Ro!NsP?+Kz^_)!MTKnj?>tRf z|1)y;S406a*9hiZPLs?0Fpbls8!cfYW&{WFrcU!c6`qVPNC-3`z z>9gN`%>QMh?Jrh?QHdiIke_vrvL@v8HvTn$ZnJiYviMi*&A(Ev#Qnub?FWe27Cdjd zW|C%N4%0j*=*IvH9T$?647_U6+SPg+qK2jbOr*RFv{wcu9$QqYS}nY|ZbW$NhOO=; z-T-$1{0!xT5#H8Dx0|{uEkUzT8y_GH`9-KN2fIZOS*25**31%B?#I!Cn1R}33W%lQ z1;GTs7Xh$7m7sAMXLKu+}E#OA-`TKuYwj(6JReiR1!Z#_~!8U0qv_J9j3 zTJLYZV)Nycr=k?+RTJr};O(}_$vMwU*B$9Vf zrvA9>Hsemt#dOgY<2Ln{i4zW_uM|4+1Egv_iDm|`e(v=G)>-woX@J^ed!*;r2jbPn zVjJT+!v5TV9?TX_kE~|GW<;-I>!A62%K?F1c_vvp@tlt1A-pC$f*+wBO=Cszl6-30&pHAa7PX(w%kKU(*{_};DO zm$z2S-;FlnI_z{DhrY0ip|_CP>2p+Y`FQ277wsw!cx4RSd!B6j=5-k7r(cLKiUiQ@ zI-kBkUTWR>sWZ>?Yh>`Z@+CYo8a30=Ms@7ZV~pNR6F8fsd_smVFH{$(7cSbK^?3I2 z=)5NZVMi_mH06bXj-6_K1OTtj;RgtP+KMt}bVLIAbeXvypvyf7vf(J16MM8}9^Q+2 zQ~LvS1^^}zu7+JL%wL_3CFn_IYt!+ISKZNw$7hF{OzG=&Tz}?=`GoFtr6-G+U)O+$;8=FMS{09K@GO`N@!$u+*! z@hcw^a9!@lXP=W?-91XH$19+~I&G$00oeHb?x-xGmDJ&7AwuJ&9x3|k3t#UlJi$wh zX(S<$c&Wlfu*QU}UMVB6H*ict*mr)mbrWyO#&;@SKVnhQM-?&gd}GLGtq1wP#5y*n zTmh3yb89Z4_0-`Z!9tzD`Si}SYKY6pBx73Sr}6OUuVS(J-#>y<`#2$!;5(`+J`T$g z9*(8P3RPb*SPkEzX})0 zS3;tMw)IBZ^EueYJE0VbGAy+s8>)t;iOepi6tdY44U zkBzxCeXYC1I~}SjBUV_&7B*t3rNlPyqOq8;r#Z`#_NDLoJb+8By|$n_F6U=p;~n??ps6l#_(!gG!Hv zU>N93HMh`CBv~=d_0wW&qJuU05I5tp@*TULz1JYskG>WT4Pl8@u2ypbsQg&c0*3TC=^F7~i+YwHz* z^KxH2TxN@FrV-~s5#Jr79>T%lH|awp5r)R2$A+YVEjOol_gn}KSIfs?)Z&vB{nr)4 zU#Yj#SLnw|Sl@2ayi_&4xaK1cWE2H~r_?dlX-J4PJCeM6_RUz6XmKaRt-w;Cw^4$^ zUz5p&O_vlZ&9}LLHMJ`VcF)}w&)v@H5>=Nl9&JwyeNB)rIO&3S6PFl zLgF|V{^`onlUZ}c+UJH^=avyRbCvz{;(F0Oen*gHM-R1r%;e%JT?FJgq)#4W04eOn zfH43o@>X#R*dqf&X1`K^nvLx3 zW`u|K=GZ0c08hnf38y7xrG$?}E8e1Ph#v7HQ=oBOgX6IL^~Gg9X|nT0c#Bd7y0P(+ zMf3co^XYdddZ6WiSKD}y47v>dCnj(HRY{p&m+1ek?DM~YEZ)@Hm2pTJ zhn~dfz!}&eea(<}eh)E;7k7XFt2+4N1dQgwVPN1gu>+%|?8KU^VKyJ1;$GH_kNPvAWhqB@ zq;F0038_;p(208TuDn;yp?NeClf2A-+$^u=0tIr>)-+n31!WvGCk^*ng-R?-n;${a zLn;F<;yvaPs2j)C zG>%>z$|g|-s#865~;3Nm**vTQ*5C+k+M9q&%V~i#4H+ciTVrXg5ip^yzw? zp*_Dn>kySZ+dbK#Wbvuga#+va9FMiUFK^La+$1S4?Kx)oStXYKz|34o+hgRaUNq_f zLbzn3vl1QnjJGGHKu&Im_C*wKn1U9KGR_rQ?5N3pKptY!N68`2*4c3JsUgJr;ek~Y zt9J$yGmfRvb*1@p6|rs-Ic@2%rYV=kYrA`;`&9RZ@n%4)=aJLcps6&Uc#$MeR^#ut za|%ap2eDrm42cd&q=y~28jg^nz(KBbDb|z8Qxfl<#m6cg zJ-XW!GjXVSe?7`|d>fuv+py=J zaZ4nuPbmOU*np`}eO0;ARIG?)-t&aS&oPtKz@0K`Hf%{Ka0}m?o`_G?js3o493@Gl?P%LjeRW0hHJ6t99{ z;XzQv?53#$SZ`nnpJk9`GK|}8jtAZ`CKoc_YuYJ1wr#@uwW=A%BiS1&sNv9P5$ZI2 z^u}N6;zIjn`Pit54FIicqNd-~g*r1uS5v5|K<0@aH?;<-mT-7~{nr_FlrHAIq^JQ6L z_ui`Hs>-*EI1wIDc$GPCWW0U-o%tLC2h^5e8HrP{nvp+MxAWeA5G#^}Npz@&2Gn~g zbHbWDffu=k4uqw2~Dr?B^C&_X3)NwSFF5EgDZ zdR+>!cj1~zvVJYQ{vAh9t>OxouY%fmiD%GIX{6+NT{{V5+ zP}y2$)7{bDpJe44XsX;Ol{ka>^GjzvkLBTibu*@qpfOlQdg8dTHWsG#Aetr{RB;A6 zE)yH29gs5FRLJccpuHQW_v)>`bL>p}?Gjmg&kgpIq16OY+TxHGHc4%aE&^=kps#q@ zqehD%#7De~bC#ZR54DK`@$AleTkJpn9q1PB5lQ_sub$d`r1*k+O~AHj`rgX&7tWVA zG#z>af#d-Wb}dwUd_8qe!Ik`rcy>bqqyPP)_)bmuM#sHb-()*1BAIR8ws1iPvS-z#!4-!Js}&J4;`HMWjBDEIrh_FtGgsc9zzirt44yA-GB38 z3;qrtcH-aRegCxF%N%>PfEi$i++LF5m;or9N&ud?UWfc09x{kKwn<# zcc-j;Ek#9QkdN@Ch|gU(W26tU?^(s|)P>728zlQ}G$zed5HGnq$)?O`lPQT{>SJn6%g zLkg@zXtz4oHh7j=wXSJu9X?-EWWic9!P@q1yEyOe7a1Bcyo?q4NI@7R&?TJPo0znx z^@gjuW!e69!x<$CcQP7*Am5Z8=~JwObcyMybWXTw5Xv@>F9sGVB}`~>Uu!Kei+)Oh zdEz3vE&Zh5Lvty=(+Ss(RqyL@5OrZ%oI2~5(T&TLegfaNk!Fy`NI2gToOJI-mPbza zy${D}@*0<1#(mNc;-BO=vgWgqd4bNil1I=5KEBKJ*6nWT45PwyzPkHrb^D|Aue$5}5X1U=yy==Z+xmsD7Ek~QnJGLU({UXl z#svwb*77hsjfUrk`N(z9-`?)t%c+YCg(Z>|;-p_C3R987wyyTYE%hMpXkimqvrjO! zb0ASj_mM0B`8QwhDyR`xMnfeg2&&=;H3$OZ1 z3Z5n+7=oo~jcf=d-NmEIcpGNr>F{F021<=MH|S((PMF+F>0lyhu6f9iC6oBV$Z3(- zcA~k@5KlS-ZtGfYleJ~Yn;#$|ALhcm${d>k{^$3jR6fR<)11h%QsTJ1aAc_dX5T^p zA9+`;&S5aMiy8OK8nCL2`w}BrNXTt%cUO0fIvD5GNhT==I$s8i@5-X2viIr-2%=l$ zqZTE2DX#faiw08hLeEe71=ZUXsaMITW#mXhSwsSqFA%0?TBHAPV1(fe%1*L&o@42V ze^P1kr}(NVA~4Bw~5M%ie8ggY8cPz0dU=?s5>vSVQUC;|wE%b(W=G+oX6sI$vJ zH#gsQ)*@LX`*esQ$&q)7FUP)SbRxF-B?+h$8o~Tve57Q~HtQ1I zMqg@q*cbUt(D9MJ=={pG@b)6UG|di}WKUAo_7k8;j4?k5J__sSKlcX8bvzGWT?_OA$G!DbVKN?al#ow{C$ zp(s6)NSKHDA%9QaP4smxv}bc*ZIfBDO$Ewg-)fV zS@i*9GD`b-mRg&aA#yU<9Ob34oyzS}3Ndpo;@vAU+N*ej)dW2NceiR%FNGzuPkLb5V}|uTi%>667kh62p$wl;Om(DV1${%(K5Z zqf6>emg*VQW%p_;W{3mDCO(bE0utBHz#aY)1l&*n_8npX#6-cEha5<4z!f3^$}VLf zs1KU(Op=Z;Ags5{Jk`2M3a|rT!vHXF`4Y%i#vh>D#GCc7Y9e%^i>+ zMtJm&=`kMQ+XCVo1fX5cQZR;$-W~%mcb?zPSXTPu>VNe7AEWM%8TWUtHX&UNsq((V z(c6KADmo*pxF9zn0L-}Kpg6;~#|VV|uPbROl^Fg_$AGjKJez@0+Xw^yBAS|6b}g!T z?ld1je4oRhmw=5l#>w4bUUHoZsMEI-F2pkc0m7;OH$kN*^c{GWo8z(wRWx4o#YY9m zzCQh#BR9o@DWSrrk%_A#TafGw)cbJ&H1rraYo_e-0rDJWKaq18&{W&Gh&Vz{7b>0M z`pz>3NQWHdJwth=mmNvY!9q}P_P{%>n1RWa8wsa4nj3xxn-XbLL%CHU0b1r z2**Zmw+51cEs0={_3!exQo(-q;R&Ak%=s}NS^f3nP=L}e3F@H?t~rwngSD!UDKYB7 zAy@yJ;>W}8qc_J_no>1PBZ{~$@4QI-9xIi~XZa?F&|80hQKO`F;&kXYu{lP>)ibT} z-Ce8CQx;9eR& z-`Lwx&UTdRUvdMPU3amtr{bAikn-7@9K^1lKGq%23qrR{;_cxLHo%Y$2 zmyCHl4s%mMb5GLW5;3HbN4zrhV}`5Rnb3_l-Ouf-8MQq!Y)HUad$!l>ytAVlBiYRu z?tUt=aCKtOk&iXZJ9I*UPK;z#Jg!=kgJE)AnrGUD-dgr6e@_}w&KD{z3--ocr3B4(}YkQ$`%n zZ!NH8Jgf@umS!1Wezy@>GRtjC)M9g)E8^(XMWkCyEplPn}F-G9HkgO z{gc|)@|c`vw`6dqChn&DR-wM_%HEAzJ!2AsYb$wQcV$@1x25cz6U++ARK@2|WRjX$!) zMNG`k=JakWe`AlAtwXBS+im7mg!}PX2`S;Gvz?z%<@9dVeIa5x<=R*=^K=1%S&0cgJye z)r>xX?YyFsUp-H^^7Xwmui@@F9gxP~Ru85sD~PkB18@6u^$2374tj<6-4_Xc2n!aa zvtH$4v6a+!sIb{=Ok{sH?ISuXje7*23MsN#k!h*Y9q;+dEH_$!|2p#pm!eeRH$BNq zm_tx1BLN>TER@GB#^78Aa&_j0BKV4em&V&K7YwPpuZNtjaeU9ropdo4G#pzUbrtj3 zxi1$Cb>@@1J~$BV!Q@^v1y`_lqAw<_;ndMqROu*aqmew$#Bm|T4rc8lCZ;~NN=o+X?C86?Q%m~f&7UIm~@@{bKy@5 z`Vk%@%z3-umRiVKv<-`{3bT0a~t#~L0@7X0W8hlGQeA9Jh zyu|r)Bu#ar>o}QrsNAvf3~^(bn1qtoL6rmB*2^!kee9m!8=twAN%d8nmuOSyY>}_XhZ0Q@&yvs9kWxEX2=v=wYNwTXz-)e}EKpQus+munjz? zv2v=8@U_wmp|M{NkMLrsIr^uBPvD?MKSJ#cx!^6T*6I((IjRe5Gw2$YJAe z-SX|ffF6xyPx5L+oF+GiktKvO$16Q1Et}BoiO-qa(yr;SOg6EIZ#iOwm+0zPa&}4Ut-xn|fhq&ByI{vWFunlAB4*s@i2Y)qAIk|PgWAGv_l-;RP zeT@9B2b**wwb-jFJN>IiGPnFG!`CD-qMb z8dkX6ck=k-eq}=dXQ#-C3;UZ9i6~#N>b`nVRx>R$5fe>qwWNIRi$6?kZG?1EY)mV? zU3>n0t)`OGd>^YD^s3UZ0;#cNsKNJ~n(m!~C6-4Ymj4oi2dshK?NTkVvjTrrQBUDU z0qgyhn+%hUu0%Dn&YiiPG!{l|FQnzS?+Q%#HQR?Ju%}O{+0&CL^IIE7tcmp0Uw(V; z<@W@OeFWv{VUKB$2a;z~?-l+Jd+!|&SG%r{j}SyB5#6XEI?7$Sm*-VzcuI?;^~ zy#+x+7}5Jg@4W}niOwKeFryB}peP`#W<-~5AJOBxa@z#R@dH)w?8rF7SJEGX9*!w?c`=e9qm6}+ImHw%462W zF*kBRcupCtKueR$&|Ske_d!qMuzbeZr4e)f*z1ufY2iRzdYPfx31i%M`+!ch@uRjS zi#M#$rWwvSgsYvsI)gD-$S7}EY@n87Jx=GV4Q}$t&F6{6kpp%O^YY2Gewk~llDmfI zA+6zDEmh-!9w69DG8d{9{ik2$-+a87c5|?_x8)d{%j>Cg*mHekaJq&<>zS2iwG?{W zJJ*te0wr(V2|H^hw*w7UAQubsRV*terdWIsS2-@#q{IYLinhsD&YW`ax7X>C6hO~6 za9_tJ$z#|d*dWi=)6<`zQvD+h;iEKgg-pgXlA*W4Q-PAr(qDW@A7IzZ9;m%om+3lS zGF4X<-t&1<&QJ&~7jRLF}s*?iE`A&o~XHEc3z z>u&$ySW+Oj4s2C*H!GY4&l&&DRyT+%EI-X*G2L~SqsFyj&oV)~{;}He_XeKV{F$+~ z0#rhrDGX_hA4y13GydQ7c7%*>t{u#w93>u1n{oPRv6Pt6d!+8{9rK`c+yS{0pyDx( zKG?Rw#N6#Xk6OyWbM0Kus=au8JrJnICMhAeSJ=X|#>J>ccVM;&zJ2o`byctDy;p^! zDSN;3j_o9&z@hpEHXaPuTDps7KDIk&%XmV-U12~lSVl;ot1O25Mw^wSjpVJ+wf)y$ z<)uA9)V<%Jy*bdhL$PoA;Aa5CFCHsDIC-D=owl;pzfEz5aeG9idX^VKuT_D7RPk48 zEx~U*(Ed@x{=XkM2KZTj6A9|?I1h&bz*zEY0lF~YG^mvTZ`Mi(lz#?&p?SuVK?79l z_b>S~T0-C%t-sq-@Qcki%ijgMZ^#(4cdzX9C<4Zj1s z{z0u`aA6b|CInEi@PH=yc>GbWwJf6w1Oq@BkP7qRQt${!tP)b8$J@~JCxkM8#FI$& z^2N$Q>5nC`%kai*BxD5ZJ}4ijGl{j_%!(XY{focr4Gf@yz)~nzjOli#9!95O6(9TS zpGBh3QI{R9XwI`c`!WFcHX(%{Nb&%#^-+~~_)m~2c&gbP_?TL)4-Q^q8{|uUTH>*v z0+PNXA(+TbfPj0H=WjlC9ji{_St5TlPwK;+)lz_Y`s*W*{|A2WGn4cQD`QXPZ3s9_ zY-DCp$(yR5f%My1N}cTX^Q#TqSvkLwh5u>WKUA|Cj0gH&uGlh#{_rcF&zRSjwWo_* zplo^eMUz(Yb=)_?MwM?+{7Scn{>Dy**R8XGbUH%JpsM&D zC5-dq(S0T$f0nf$$pMv^^V7`a)I?8Pa^t@Bh3OP#Xh~ps^ z?SvJEoIpAR&q)`dOQZn1k-LsrL)mBeH~V;!YnMw|HY>csI*fwNXXidXh!xtF^|`%T z$0PYYsqIjjJL~CCkE^^w`~mOB7y=D{B2Ahw&L61@}xZ2F|%<;Sc?DM ze{CI#Oi&1bGD7qgPMA8lb7S8t>Wk{RM;al*YfQqeV1o)<%K3+ zYK+X%?4l3N?XL6EelpG6C9t)&Jk?bLDvSrgZ7p}u?WGvPsk~;Cez*V&YK`W+EVC5} zKX$k$%zu8JZEjn8zQmp?5YLJJ%|l1rVDoZ7k{hxjPvT{CsD+BH&Ieo@v)fX9(g*dD zcSQTX1P{F{3i59Is``}|b+1zi8TML^8fvj^#*X$ZR?oIg;HVXcQ60miEg2n>qcp3} z=!TJ<^c218L~fBs_nX9*soO;^;1(duGZV2x@}FLL?-ZA=c$dY ze!R6mfUWezFJIEMnSsalWE7F#&((dosq<41q1E|nTzzC_VB6w7qRfC>Cl+7= z_3THb5@7gXVT+7N{aF6*=z1w;x;UMx=y^alkZi&5sf#B&?G&EKT-H;S88FYGVQZyc zF>L>!`zpva@EbKeB%i? zR??5Zr2>!-Ol$OZQpO@Q1PT@{`f~%Yz=n@y%+XW@|;$1dP ziS;wJEJiEcLmnq|iW>dktmd|;e)cj>T49=G_tr>TsKwlCnM8AX%so_C7i>1M>zq93 z$lq~k`6noh^Mjb|tzmN&`re44kCE*$3F^eXR^)8r&IhZn#&BkiN71?9U^yxSbSy*h zevH2M!x|kEw8hx$wteBZ^2L$4KGqnWbuy)AuGbh-(Y&iEUEo>GlMk(va)e&y%iS5V z=l8{ZVkT0nFH0IqbMzlBS=UuPpE=SgD-QUq8+i3J8$Oe*HP zX{VelD-%Q>lne1JiF7x&ad@!XvQVZ1>iGKR)KII|Yv{P%>DDXzV(RFZd9Bla%0*r^ zJr}wSL0{R~KX4oj+_&f1{RbOFqi{Mw668n<+yN%{g^Vaf#QL#cn^@?1gTo zrSuZJx54%l`X*q$J|oDiFnxWm1Zy9EdV8eq%?_O11Uek}je(hLYj%$Nc+hL`V$w`PM;;rB=9Y~364zX;@ zr);y&kyHE7AwGS#-s^KooCyyL8SYhFn3ejY*bUL^1$J(>ss6pOf-M9b2U}xGyaxSH zfy{l*!l=PRl9y{eIEk|TfNG32282#3_Im~>`NJbp7vH7wPlvN6tp14a8)t)TNZ)Ut z(Rzz2YUL4br2e714#PbLs_0(X%lknmUsJmgok`g`VQ`IF}$C77ufc^ zkUcoKmwGLOebi%kmx)|6%`6q6wuk8&6ej2Ei0VP(}DfhCd;gy`#5K1r(GVft`z1+mLH^aNuzB%VNm;d$#~~HQgii>U^bFih=jqUFGViWmu9rdoqhV^@b3@*#~=CBLUI8?1zMxq@F%_ z6btsV3)LOh*iyf=Gij>m#k3P_bK`2$=#K5f1%Bj8=f3%rdms^-Dy0VIdydquUyhG< zF@Z%lL5hY~=H4&eZ>(haBxg^HYoR5o_{g1yRm$ zoYiEIkxRvjC4bEa<@r1*vp$$Yd3lI?s3QJRHO8cK#wYN`#{52@P?Bb<(5EVJ)%@m5>KrtHi( z8>(Rsrx6ts^s}?LCs~$Vn%B$JIwd=cL9PmY`_cMLSJ$gC=Noe#QD^Mwm#8@)&t;bfMUkSoR7G48E~ zbI`BJ(ErpHzOsKtY7agEK;%sN|BZ~djHX-s;S2S;X&Hx?zV2cRy6OdZeNRr|ywYE6 zS3e(gPP}S08@!MMt(ri{0nl1T)1m&Xk{^!!PpF82jrN^rsV}modKEz|{8Ht@WJ5+!KQ< zh>nm0+7(7(&4H|ZEv6N%E(mm^zJtQiqX2j0#ZM6CAP!i3=)15z&BvlpOSAJ-`Cm^4 z0aIk+%Kjzc`Y9Z%3UuAQsrU)PdPB|u?JY1e*&OIeHMmFi<}ouRMaUX^Gr0lE zs3ztUb7Zd`anB>tfg(OD{e;=3fSYS2F#mO@gw{{#pgX2K`7HXSTk-E+D;||uJ{a)} zC0kA1%~GTffj12xg*vrDhO)4&-p7wLD_Z)!IiEMhbKcN44SVw| z)In{guI_E@mdSCtg(>R3fus53ChTzdSbi1qjbDBPwhiqm(^d}5KOxpU+c<}zvVVP9 zpF68f=i+KU=I~MzJ^Jg*#qYGA-o6YP$9iM)F*d)xJo$zD^9^jf?N5*lpkj*^_5Y6p z?AC7>5J8_-0fQG>2#h(oKO7?F8p(H6{<9HuSRTNsV!;1-Ouh2WE3jWbTHGIwFv*Jg z*GK<9bl2fbxlJ1N6j$yZV?8YX2wVS?J<-$u$tRb!T;2pD6X!1sTd~oxO-mZ%aF6tR z{L=k?15rWuf)x5ei3$E8KAP>rXLNh5J3|0M`P}3CO}*0;eV6w9?0)BsHG_6O)s1L3 zRnlGd_Vc}3Z%<20st+$8&3H=U7;{+4o)P4_%Oi{YfEimR3*ez-)yoP#L{U#pplpQz zjeoCqkUEjWXmR0Kh>~$DG7bY&(_p^)7hA18?@eF zEg78QkS4SIxBNK0E&cX!lT~pvMn-hU;R4Ass{QZEwKQ?1IEa48fq|&Ae3kqhP~E|s z2t0`V4@{3CgJG1R%V?1P-b0o<`)7Ug_}%>D>|+h;PS?3O*SqN$Utolz9762jzw{`wuoOI;=l4} zlG{>lr@oD^LkR!)^%mW^`euTWS4>xZ zZicvUw!Y?1m9@N}P3wnz2)&EdKEPyN+TaEO!HK33b{5-3aYt>#+wAFM%bl3H2Fqp$ zLY7UISEoLx`yF#3SL z^VnwOM$aNYYCSIrLC(~_vTHPVf6QH0?k*FTW}P$lUvCG@X>d>Q*VYb2QObjRhsI9W^H3j?MbuM>h~mIl|l-=UJ>sT zR7SkvPUzeVQS{9V#B>KQfVugJk3v7YUqW>J-TKD)*@OFhuTha#u_$nuOO}l&J^Spn zWA3P}K+DX4%n!jZ+;&zS*G2Xp$bmj{^(m)_PZJ z)tnK-HZF>jvqLW)XE$xeny~dOY4>4w0*)2kDNqc9dEw$&%1kc+|3bSt^^y4;tlON} z&vGTIRK88Z893>a74n-#k$;75U5(clyqhRJn$ zztndMYHmK~F{pX6X~m21Q0dpbkML!;d54G%)orTAUry_Lo{pN$FR*G8IlN_R6($W) z29eMo1D8sz8Y??$)_KxgIeSuDR7vO-O2hIj{0DBJh}%^Cdv_-az-es>QX6u0FK0}{ z+xu({w7cg(P+et8=TlN`(}}|b-HDO4MNG_75b_w zo|R~96)(g}o?GTLZ>xoDg5~1rM732alj8RTFSZEFnAGRrX1Ls*l01FxUUnV{T9y&Z zu}7MEH_Wo!yqWcd6kczQQ}N;%MhZuTaM&oskKeaUNP4}xEZzEJn!PS5dz{*>wzgwJ ze1H2EPuS#HtGrRTL@pEFc)kc!crVb`^6 z>*FBFP=5K}EE)gZWciQWr~eyf0Cg|g7pr8{d)WxcFyc27{aF+T6MR`9zt)I`{UWRo zON64`nQOHpKNG-m{hP1?dr*^#H0aN3ll`*H*ec5^-|34R%gqX8J77P`{@?mFQ;Bx> z@u&hJHAGSUck&N^PrdeUJ@*anRMF>lw$e#kxwE1O5jvm_P4(*+5B+0rHd*WC4NUZ@ z`SEw4wOT~_ke4`Z?rvY1`-az^7A6|z%N5HzE=Lv*KsmC*&1t~*+P5=ww4idTGQl?S zGHsx)mZOk`k%~}?;M*9k(t}Binysgcc)Sb(0Zp|CtQ7w0+DT9^Gpz`mFW=>KwhvH9 z0$MNVd&gv+mD!}Ecut8FB%}9IT(8hoJaU;!@X-e{17hQD0CJiVyg1^@9|%*i%5k*N=}Z86x>e?6h&l~F-XR!wT35n*bCc+`+N`V8 z`Lx#Pxxz32{E0N>Y@l+eGIQy7ZqJeQIvh;%4 zZ5)|Sdmi;#$%XP@OWDdu1s|^P<9+gW__omS%BCZSdIYYj)ms|YScBJXLt5x))Ii}@ zg)(gf_)#rS;2QVc&m!K4itEOsW!1iyI!5E9vx}-@JbXjoWWxw{7FVgG0*|2pSxiaXLxrLl0vD-%h5WWK9(-L5U~OB6D#Oj?7cea1=OvoS!}7m zr^+u;ZzARQ?gtaKrkMM5>;fYPA*0uQ#E!DndmmQN3cP#U? zgD74GieKhZGq(tj-sXJ9kn$2R1CK6XuRe6&TA69!W#*9J{}{Q&cRfw=bVdCg*{GGdWTP6Ii=D? z3<$|Z--+Kj7OO7wn)6d`Qb;LJ>9U14~PM&}M;77}u?u`abI9 z$O-$BLP=-xRyXcTCl_P1J~VGjj%)nr-RSpm_qk0fl_bBjq;M-*Sw^D61>-LM5?k?` z`p)=`<@mxbun(WGH`rTbpue{L7j3m%Sz% za^K4Ak^=q8s~*c}p1w_zTzl^F@E;S-qp|2boz)9OsHhGLUXML#`Fi10JLYnUe;bKAzl5d_RLw@LzpQ zepuE~WbkdycBuc0+oJ`>6$yNO%B5;Aw; zre03EQMy$)Ga_{45Tyz5;Z!pbl*&(Fg42HBl4!+|^Db=QrGTc+!I$hK>NQdAr?S=; z<|{OpID+!~H9+ss5!4<7^nPV>Zd{%$VFH>`Bl!qQ0GHE0-dSiLAU1{{#TC}XnO_}J z+CEseA<#Kq%AM%3#fRFLNcB^%P{Ipo?moc7on5S6hi7JY{Zam`DCW|YX5NnTmP+v$Hi!#nj#ksN z9EF{M2l;P(V<&&;9<+vGp1G|+BjqVAYLR>SWyDbfBF35#9F)7YjB;n!@iwBZ0%gq= z(4{%s=RcTfC*7MNowK>KmB!tL3T!ku_$K!^zm`04RZ)a%!{4WM9r&rCKdq$mYK@io z2{qs)+FfJL31ujrrc5FRnS8o`@zwKV?EG~tJ2TmFjQ*-DRDG(+S%xXch6eu&t-~H` zZ9_vk!Tt-+cfy3F2L;-}U%hYO9CK113Wmw?mqigoi|(Y`3Eos(X=E)hH0v2n$+(5* zeTTNibn6z4GcL;-(6MlLMLygoBiI(PGfcaX*X&DV%3q+`T6ujCX9_>;nQJCfNqeU! z&~mu7D1vf`3v!ndySz8`{eX5+a`08WcSR!mRXhO*uFT>2vc6Ucof1iO^nnnR=Zp=^ zj0Q4&YeBU7`UHoD&0_cwJ7iLHC5GdW)nP(A3f=5cE&fz zsG|jBf~Uo7M44!`rUl|Nn4}ktQ=ar7K7Vqh;UIY{*$8cBg^cS91+I@*x`;rhzaLqW`%LJu&Ney5l&;jIrfIEi4(+p7 zD-WZ`>Xh58v?tD|Z~O$&IPH$+H6g*_t0DM?$y2upaa$(eC!&dlFS9>(BOAVJ<$f_U zNH6Y}tb0UIpKrHBFD5IYnR*-mMu)$D2U|2&DG**rmEw4sT|ev0jXQ~vKxi;@&+^xX zixR)~uzZ!19jLgx97N6%M96X^)@aW2%`3iz){mlUstV8w1QImLrR&sfmM7fStx4}; zFxzWHg?%i3UtB>$Ry$@wpOFD?7rBt9-NFc2y@8jN-%L$ro0}0qGF_396QU1Q9ynO` z;bv6f9IsO^H}r;!4TI6M1MOzClP^X^3y%7#)#r+xVRrG3WUQg$PunHWK77`6DznPL ziX*MN;CNovSSsQeoqLnt8~f`C9o=rw9jv+Ql6~l8ZF}l@MYS8`dov1g!33C`Hpx2J zdyt$nbS3nQ8neFrlKVQM!V@Rfi>W+*$irhL)jC%2XqXD~xN(ZhH(jEW*j|PLDb6)R zQdZcj|7@vQ3wat6z~a^0`Km=|0%Pr;Yd4$2>*3^JRZh(CB1s9taDQ`10EZ#M*)4ug zK`tn(MQ<8=3*7@~^e~mxKHaiJsGC~x3v5ELh53k($7WQU(h$rg9Kl;gtOoAOh-Rs9LAa(>Z4jz1@oMf;*Y(ewOpL%N~|GH>E4)OAwU zilCluzc78!se_Jkvpg9Rx?|k!cI$)zbx7>|2>X#LjH&qh4lMe_8Qrps5t*_E+&aO+ zWw}%AsfZy?$3!ERB_YRF)(+-3I0|40+6@u&y>^v#8Bj5hNY&V^k$ChXnNCmgbw|oU zdd;2;$?>^P0JqmgHx{=7_GApOtjWzY?qyK(^Dw3aB%0Y}&aeqHr zv1GN$y~^0e)N>FSmvVRJhA`Os^{xW*>(w}V^kExN^DFa^_4_6mAt;bt`#H9qGg*Ey zX}KiWx1r#bB&{TfXd-Sk<@Mz5avgoNhD>}1Tp-UcP#o)LU5U&nS=e`AT(! z@s`7Shp5J_bPhNPRXIzb!WR(PgTpx%@Z(=%1s$0_%rLL>Qp}v&S7~eJBv{e5v#nl? zn;@T;^4`!ER&1?x_H+sGDbKLpKZL!6dNRL91j^P#4vu-KirFi=k&{Sz?3DtS%m1&k zD8G|RA^gP#RJK8f`~m0?Oz#J&LB>|*dHIV*?OI&u#@e#Q_FG!kkT`xlebg(Xf7=5U zJO1!s9Wd&tPRH+G&{|k9{!|-X-gZcTo3Vfkm&2mGh0A<<*1CrrZ(%dl*j~cky6|d^ zT6W-Pp3L-vx7oNEnqsd}@?BV|$tGUUY;#gaXqYQZe+5_E{nmeR*GufEAFsxNv_E8GkCd(#1TYdK55sOQh^>BTEOOVC=5 zwss`DJ3X}e1U(yRvgvc{29T?Q$4`EOYQz??3qB!P0pE;T(o4;@kz1uX#t+!W%+{nn zLL5JRaH#JYQ&H_z+%ls;p;=I^7yu9+;y)VaweV~(u;8>JwgawTRSS7@PMN^u2cSa=O?JL+Gle| zfjmzpzPEPpX=Au{VszpNxsO_2>>^i&)ol1Rj*}}*P~)k*$+FtQ+a!=v`>j2H;3AyV zU(ohu^zY1{*UN7S$F?qMFYWA{P3!*Y=ilozR*n;Dg|_TT*u=@4lHrcuH-2+f^J5XJ zFH?9v`WomXV{o@Gso&^@;#R}WxRoJjcdb#}jKHxepRN5%)hp{$&-h*vJl-TGiH&^Z zl}T=fT5N@`0Nk90;qapq-KL821g`;sbt<0c&pqjO4I3mPn^gTE`CIfufr*+^eC+jA zO|=l#TlYz2^qKBiOU2aT`88F0>-P-f8P*0JliJN`Pb}$71`OCb*wl`dRwbH<+$&)D zI!K|${;6GT)Q=Tu^}%Ij7q`2($Zp@8k=3d;O)FLPCPK*K1N|*d=Q3K5&r>Y|Cj>co zY15}<_Bk`03zf|)MH(BOBjnSjt2}uFJb^1j) zSO+L?;l}``IJQ79=y8#%M=6iD9<8JH!dDPMA*Q%%rxp1sDZ#@qB~OnJtK6Eup}-vc zm)L1(&6_CN;-%<6<`e45U04VzDxl*?Yy)}R$}5BPYHCj?p2OTK4xEUJgx5kN>ls2bVd zX_-6)&65c$Fmi>p+K}TjLA&S!S`iE?pF_RY#><{i>jynK%Vr_ji)incRixfyW=7o# zLo|zd#E~s>9w%0^B+Kmb<>R>$JUENHkIqG&FCpL&#~(7F<)$+R5K4Og0daKG&{?!{ zy-%zv=w!%WG1KnctU1Sc`&@j#d_KsM|9VF+$&+;^-7uEp8#v{E$;0tS#}Gt$agq;?sxFpL-#swWk=QfXAY%J@?>1OHVMk?-*G)nM(CX?MUM`%WgnO3Xl;68%xBkNr1}Nikl3JAQ$M$`gAVhfi1LTV2O!1i2>2zJZv`8d04ZBXYOr z(QZ0*UR9=YGpugZRVm~G*|*8q^BlZlF1f23BE%w>D`DkRw?o^Q- z?`AO8qv5v->AlK&A;FJk=Vrfpue}$SGvVzijy~SV1^Mv*E`IuxZRx)NqLsQi7vGE6 z-hScEDhT`!tPl5(y^wyN)cwtW|Glt@&axA!y^(yZpGS$E_@YKerH4Id_P)v?mEtITZM46q>MzD->rqN}Y1Gx^lbeQUl1D6uxAaO$rD}scTD} zE$m2|$m2_Ob>tUxu`-IZcP^+0nLAWE9>|HOQ6((}3d-l5_k?ExBryuWItIRTE*Qy$ zj=EYKcGPS(lNs6p=1Ajpext@$%aiSvcxdUO+qj4N zWO5Yi%dO9gS8E72`03Y4BEz_N!1bBrEXdXnz%D3YQ12WZwk%PrFA>A>z?7oNWt;Ou zl$7p8k*1liex=tyXA9T3jFTlwu)W5%XdYrU>v0_X;B(VdkER$i7xb;PoEnJ=1T-+J%)LKBJZAMu0-(DHQoJ$cGYW) zyp|VhoK~Ebs~sL*kp)Tcmg1U=AMuk#E&};mT+j4*ZfiU~yf7+CZ!zY(@_Nx8@a@Ep ze)cb(`!Le5}} z=304Y^eEbcNxh@u+mNT70Bd+0+mdBL{5x?zW{8*h< zW~|Nv=6nm3T|Wm;Cez~HWN{y`1SZ=>^!4_W06b(fER1j6J`sN-)$`(Tn00|8rhol? zhKRG!o$gmR{!4Y4;2p*qIaQ4q##PTo2h8p2$9UMXXl%kbba?9rk{G$U;A72z$~o?L z2Kf+Xu6nd*p_iO$c6syY@r(x(y_zBOHEqsA3%&w_qMGlIbFSR^$eaX+x}XHR#78%M zP)dX)gOl@h-fm z+OJr&mCz||O3{mNd2DkMT%LsHvYL14c9~tm+%if5fUq!$#oM7vny*r{5BT`kCGfe& z=0w!^y0z{Ivw&zoWI2g(b|}xzONQ=KaijFEQzOU1yuF*JH6mvcl*P!My3nh}buZWt z#q>MnNsr>lcBs5!5$6}ilZ%3^j>mLw#vqhZw`q0nD`;{N!vd;s25kdyCj@2GQT$?a zZe&S_>gv#Ix+5RhZ|2ddf)aAoR-Ku%Dyo=t5Yxd;@=nVe$dr?XsWhrNBlAvA61_@g z`rVjyLt5200=Ohps*+;+M_L3!J}Dh=%5RuE<9>IoXr4@&8`e$=F3?%3#OEL0dT~gE zDUxLRD*XzsfSz7yw(njdIgTUu@>$yT2^p<9KrF`Z9qd`ew^;LJ6XhI0jea2<@|Y6e zhv{h8`O7V8+!LiN9k?I*LP3p)F{bT`T95DaAQV5~)~zt)u+msu$nnmhV?vzVxTbBU z-{1!KN~pqD@)r9Y`dDs@AYl^1@~k6W5YEw+Ksl>v8OIi0bQBW1;LdNXb|AQC9FT3} z5P$e`l~7HJy{^vVvpkP{c>d)tJ|Z`RkllT2pEqIZh%OZt%Cv584lj5-c+X8U?GJg&MRWr z*J7x>t@+^@`6b32RVetw;h4d?y56MNbC29Yw%gkr!wz)z&BA8V{4s-mjq=SuK~u*- zo^M55Y@cZ~`{bP~_mez!6?mBBS+=A3L1@Pb2{kPEP& z)zQ#=lH>!^MLUWI@f=0E?;-f#ErVS4zfF$}|591nZvA1O1zBmGfwe6%M=FWf){M`E zv0ud$7pAT&s~Kc4hYsx+~S6eU{*N^t-W(ap&9lr9O+=w8V9^QMqTc+m*XmmYJC zrSca#UC<*ufY|;XV2}h#+wp$DPN2Y-IPwQp^2qFez51`a@vmp&Ut{4PIy2<8RF}5p zsh3hu2~YHjsJ1~Hu7W&n{6QC+;V;z1?u5=Uvc#=Q;1H0{bBPlP^7XlS2=8%6o#h!(tpPoL1arJo3QpN`@LeBhg=}lO)5xDB8=Bw2 zm?KHk^MhsVS7oiXj{WuQy>Cu_2XQ8qyM#Yg>_DBu_9X)HRjL-YIUi^~an5MdT1&FWD!ZIRyUas+H1W}~=GU1d3`Sn+jUBMtI`6v> z-^WWnct*g>6RPu-P?A9G7)Z7bmx5tEJ{k3&{M6`OLIo*%W%CN{?$9KW2z>9^%!x^# z!=DBnxx7w2rvfM?1&)@n#@_57l(KK*F~4~-@#cz>2w+V@Re+A5`b!>O9XwN$iFUU4>B?XEnvy+?(6I8hzz)Qe2)M)9W{jjh zeWAk+h7m%(_zk}YI#h-ih1y9Qy!B8eY6-6jh(sQ#wH=FU;7L%vFJm{ifgM%=vMd*zCB5AaS+0j=#zbx_D_exr`fE9$Gf)S3)DECX1FCDZT z7gtC5kltxMqc>M#It%D_&6T~(yHf?D-8UxPxf0af-*!Fx+>h&|MT@B@suAk^XwmTC zuNKtA-B@sYGU5~mg>5~F@#3x7=sWWdrd(BoaO!r$6S#B#8)*P-*t`!viJ-qS20(vXOd6L z&p2UKHAA7hr$0gJT<}cZjh~?3?fR=9?f;@JTjthXA!Eke^jwmI2TQUH9+`%i3`axP zOn_db8tA#O4eqBP+TBmFi>%e`TAAdEk4OJ&gY7?qzxcPjr|UUS3H@TVJ#CjAvX8)F zjFsP1*-hFU6YaBc*$CaNG!^@^8Q8xlqkobzI{BZX2!Ase`g@J#zY`q&Ck(^CWXS*H zhbk_+*|a;H#AZ5!Wt!_kEaZ)qVb1JuIZfg0>-U$STTNgrJy+Y#YTEVPbZYr>U0!{ZX(FJh%y{tr|R^)@h zgk_?4ufuJo8*--Uhf2Hq^s3(8nmo7_9vwW-Z2yA?gF^3Td2MuoYr;Cy?HAND1KE^yk zC(^uWGF`sBr7Bc(JeBx7Ws&4oIPKKdH;xp$5;@5saIQ*+GD|2wEWY>h7M$+Cu zJoJTLCtRoz*zEa`9iPoyC}Q|8v)q@$rdtHiAt<5&gmrL}K(;>cuwTAwAhHvmA{c&Q zU+kUlR%!j7T~dVy7k8{uj?2rf16Bpyl}B2c-v7FI14R?GSM9wkQKfP)28l%QdY@3d zqOqA(CLp;{xIE5s$ucejS=n{c@V8c( zlK&_pQ8HtBRwHN5;i_{B1yuYtBU8t4DA zCB&I(rzcT+%}F+?OY4nV(q!BKH~O~RSYI|e*G zH?_{+P^pQZ4i8Fj_vZTJG8g6zK?Rbi=LLPQge6>!e^^i&eN({`1~VMXeDY&At!(A30IYgMoUcRx^x}A>#c(9{wxdYY4Vn)rGpZjN*T>TBMG;zh>UtBA)U-V^#!ZY3YQ61u z7kS!71G~mAbI1Ea+$-hDq|=YbhJLCRW6vk8T9R<9&&|b7XK_D}zi$=7%@gi^jB0%& z14YR~pYP*hoM=)t!{NEpCDql3HKrO@tIPWJ)GRFAJRO)hUc8KFcO_RKA0xlHHEZ5I zOk!%2L4_Kcikv#-xz&n1UZ}4RL9BnWe*QsUzAM-52;RRR0;a(-d!?yO!dut_CIWay z1VYQ9_%OSaw`XA*k*3KN4+FYcMEWu-sac&>Zs>2)bU_18&j~ux_CsM6Cuw&f|14asQt^z(eI=W-!c0Gp#Fx&wH}cEtg7Y z8Ao-iG}krx)|cjF*lO#$Nvq@rYBg3U(7|OclLcig;Q?JOR1>1ZRL~dp2V199q(Zw$J2<_Gx+dj1pi5YUE5pY-1UQJ8~<8(fCVfsFyx zhN$J@&C-peW17m)jd(o`VfQK+mZ@Ok{ zX}e^>nU60>Mp?-&x<1TUA1AmO&QV)6+0I+r1OO91UAB#XUw3A9g=usonc^b zKYPGCU`(b*=OCqbP{nuZcmVVAGD}9S%#R#N(DSY7*@|*i@^rV+pbr_0ItEZQZs0F1 zi5IqyiokcZe4#pVy{UG=ss5-}%%N-x4e)u4bPwBxwR=Mm8h!RvOE+p|>^S*E7l1T)zgPvvZHQVg$$ z%7o0j>==7=`^kJpsiZCMO3(Ee0c^U-$f|@T^%u-Ajvy6*$f;4P@+zBq6w*okYpI>c zxQ^z#9n5lo6fT3Qy>4qgDsi@H$}`2xAt`@GD=W&NCXP?sb%y^N3E<;6VgCUYhlxso zo&ZgUD*Wz~zg6CswgVRIJ7UdxONyiL4U4b5qcIvC3!Dv2+huwbGtdPJgQryUh?W9)GSD%d zI0iI1lwSn|lQy}pEPh%ARAnie+z{l~Fkt^X>SKPKJhSF@sqaKgKJ0%9v-kDNcE_>6 z`~TXz@<1r}^*>0c5LrS@Wl8p3*0E$uLb7iaS(79o!zkIeD3rv`XK6?Ky0NGP9%Vn8@P0p^*G)69nx zAm=ev#p|~^5kZF>+5LnyQlMRGV~>2ir6OWH`C2;yqPAse()4!s z2A~kp0H8vm1rElETGDEvo8vEaxfE(1i=R3h#&rB+3)i*7fwq_AKrHObBD(I$IIq0- z1crJH!!&DT+m?kC+&%S!+Im(~A!VAV7D!L&u*h&p%<}#-vWBDm&waF`{r$*dn*t7Y zWp|*`AA}d_HhRfyGHLBo|3;k4G0(!9Ck&MNPD_&UKwri1ZQB3R{`Maz9?{VHJ-U=$@jO0|;(pow_ zm%i!DE4J{5ws(;#&o$VakAd8+*wCDWQ-}t{HVshbIm4Tq$xAi`xi!jI;f%uTHX8Xs zfP4%URNQADmCJ!82hLcq#LMn0yo;%94^?v9qxj=Gpq`i=(0Ic`chn9ji2vz~B8ymS znNCsWuH~UweU*Coe%q*%`(H++pC{w2Qm3jxTS$A#HZE|wo~J5}pX?IY2Nx|^W+t1n zYTlM;cXUJ3R$nvSZ^LR>cIf&F-Hm4K5{2R_iMc9vE!hgkjKCtY&6?AxndI*DT-N5- zCSS-pm{vsLZ<t#A zr6g-LVymAI-Da>St@6d3tr!LQ$vEw&-ZFryBwhnGdC{-8o@$vb4|4AguudU}l;wrj zBn~eOX6EZCe$-;)biIG{Vxxj+7-)Hk19!2c8^@0HH9*#fIp0J?O%?}eXf5 z_lbRY;gD8K;M57So~vaWkySFd!zG;_OCcMH(xLLwnWKX<8}Rc*@m(LA7YA*xX;f*L z+87~k)m;-Eifr%Cx9paH+=lI|P{_4bbAI7$=EHW7+vT-|!1g&1|>{3eY3K%&Y}5onU85j{+*%{`jaNZY&SgcLyuHF=9IvfJO4bI z1(Mbo*s|yxe0>3kTeJZ?&d)A;zJ(Gc7X19ff}h^+#5ptegWV_}eD#jkMy-r*-w3Q7 zK~Usvo5BHgY^d>kfuyhiY52+#u%(5Gd+&f00TuvkGSzg(-!4+W+y)Vc5@+DwGXoDl zVd^6zKSEHW0JNH+))g}K`2+;;F&J441H`$&qUF2ue2L(@1HxdGz`2mG_!x}aM_<1K z)~+7m;0m)d>^bJ~4ya{fZI$|)u_eak(fUz;KN(D8y(5p|vduy@HKPZ$`R?TOYdOp}WV*KVjfT%u}-&T2H2H z7ky#`mUmsgaC?lgi8FBxg%&?kjIBq4!&ud}KA2!tl}b7USD*R6eqd+ITWiB}PCbJ` zsG)r$(5I4tWE{>)*lPkk-z^d9vgU}B9CzJk8L6t)>q2Ln_;y;T`#vn*B+ZIDMbEAFYn|%R~*+G#Z#zv0%4k%uuzj%?Pva7AJ35XgOcy=CC+>TkDQm;AMtOWQ=Rn z3?vwOzcvKNODHd#Y84iF)*MTJLMN7~6X|Kwr{ZG|wobIqaxgFQ_DB2MRa@P=~UPWLw>|W%hz9@Os z7c&d#Z9ev%&Q2XQuE!qjJHVD{v&pK(a!cvWh5SKz+FI-W1T|QHLbdg7MX8z4OhoW| zp`4dp<7)mxo3U>>?^e(9oLsqjE?)icA-b?_QhZ6e257x-K(k6^TOh&o!(#C$VEk#}uqjgAW$$ zWq4g#R+_(D(01(*375f}=URdvfR!&}b8%KtHLhVa&moyc7`a%8qTTPM-e`zf3JwnR z=!e#qcK6N*8}Vq^lG{a)U%E<`%L4NEZh9$9<#nK5kpr_4A#a|AeY;`NRiWOSZIhg|k^ z9K}3`gaZJb6U(c+I|%g?Yi)f4&?Pw-j>4|pcQ~sjBbgQs)k1sL8xbUWDtyq7>H}&M z29{5jJu6su_O5Hff*Eu`8Vvt~kp$HMu8Oh9i zmm(u%N9IHxsbzwS^gE|^Lcgo>4B(#LfZS4qpwri*g3+ntROrUQLYZfeO|;Xw0S5}w z#+&~z?QB?EEaUwuy293w^S^+I(-UGZ%Lr6uJU@fH>1~#bs^b2P7WU?;6ZD0JL2TlnUKP*bisK4!!}V z4B`T09vim!M~^ix6WS)6rPj+8X*Pw;KJ2Ug> z0^2sOC=qC*onVO##o`!zG}DPQxMr3(T^>mit)+Tj=|4BM z@$*#0&#%6zT>f6-!n%;I1jy;HjKhT3TL^*g#vqgL_MoRDM}IKK{3YUnHr+2CAvS^J zQe(Y58&E>r_{m-)eb2c2i&C^(`B4iV=+ygiuKwjFi2`vTae9830pg$^W15&HRK>{m)7sCXV8-5g>1$W@hhz`h-!q3>)=027S}` z-;-tjSG?!{fxe^^FE^c)=M>FAcqe=U&XGgAkt)06e+A z$zMo(e)q9-lz>fp=~3F#=#ed_elrBAIS5`NQ`#L?>+5V*9`RAiE0rS8p_|%L?Oa}7 zQFnH1SLY3NcqrEz*H&WjKQ1B%TtRRQykH8KV0{4giR-P->NvBqRp0g*ShEL4`ZHsc z+r5_1MNPfz?NVI}~2(lt6cVU{5Cnm!$42Ifuv7v6 zFhEH8?%3Tdthhf+)so#^5m4AM*OmzVfc~yerU|07DGHMF3hIee@mC=K9{N1}=$3tr zI3#JAe(}or=KGg6bXj$W*^4#r6nZfJQz%82uY*jC3$U*vQA$j`K=M@*kYAARZzZn! zZy9Gd1j}))+cb*%@x<`t*&{#aC;tx0KL3hwC)&qQ z@K14>F6XtqCxu!#)jM$*lFFXUcJ{1(C@0Ewuh)i7f(be(Iq^w^xI$^-;hKFh{wBxI zOM?zVTkiU>VrWBPq^^Fv*z|M2X-;-F&7)mz*sImI2G{}z`7MTnEKZ#c*(y>z@I}`mzf3W_A0A2X~0s)sdHA-$wV>GR+O=HIJpg5SLuw$`qOVyLDq3x=p zsrOz|Q`~YL7#y)^9@vP_jd7peG`Fb8k#d|KO~Aph!Q<9^C>HP;=%~s=0Gv z-0-@=+f0^^m1IboW5(D{G@=2<>L+SCvjbw8haR)fm`(!g955+dE@TFWn0#5?b?y!*aXbpF~#U{>s`(qtR3ji{2jW)Kfv$Ler^AopQ7> z)g)CKn_A~fA$xIRT~G)xMQSf__B|4jin_sYy0u8vnnYV2N4lc0IgKF3!qVtT{-Q;5 z=aN3qrM%|h#*rP+K?wzGZLEug9~maFxVBABL)a6R(U`7$?XDvxE%waO(Dg>PdqJax zdG8ovdCA7D2ZYV>**Vu2#K+D&9f#~5p0hqMA!{p@s1}El?lgTR=JMciRurG9pijXy3oIVG%wA;UJbB0J@nol?>*>7`J>dpbC9mS8c=OH4_qRKW9np7X4XU=d zw%a#)JUW;_h22K>#%!z2j&Q^4n5ATW3+sy`u0zCn7v;R)A}#6cgvsP^9j9OKY9Un~ z>LFQU4z$6Xv|{f@VG4Q^SZCjmPsCGk8D$H*)1P`bTXpLJ{N^-&5Y{ctt6UWw_Z*Ib z9mtK4JSo&@V6OS{4o3U{)5SZlNe_TtqZ_$EH2mON$ez_DO0Vq(@O~GMY$L){gRawx z>4>FwkrDioN|@lq0r^+`Ew;tyMNTBs>VLbj=}ZPtSIf%TUVlr^lQEZpEIVkX)sP&c{Ma#l_{U9thsee$Hd5|PZVnF)f`!fwgB^PN%L~ce$NkjHL#q_7QPRj6yYRAwzVX-VFEY&4XE1tT1M47^XCXVkHzJGER} z=1A%F=qrQe#)c;}+M9IcIe5vItZ(@#VmR`Bb8upqGqU^7?^A2X+c^S-++`*Ui^AEAT2B^?FJ?7?>^@NK zEqP2S45ojq%*uZh|0y4VKSe#==bQO%fKeTW+kY;~_Lk3d{yQFIRo2)&x~_h4y+3 zHExp30xc##CY(m-oUNr+;T_>B(VKk@$}L#sB6W*t^9GU#_0<^Kctuy*>1F8Xa9JsP zWhcbCG5Xx+bP0{UHeg;xTL2ADUGYrL&vU-I{$@^v7(D&;;OTcz?*CUb(LUt?XygD! zOIjQoYH8jLCCI~WDZw_;^RmmWl(RgPL*j1w@WmAM!y<>J*x2sVVH(45y}O}4^;!&Ji8PX3S?wnxhv+Pxqfi+ZLiG$*$-@7W(9>v`Q zIEwB&19mab2CEZ2dW6HX6y&+iJUSOUiC4LnQC|159ZS@>0pe+6o?-mY*4I9@mJ)=^oSMgAE z;OHI+ejPXARhwL%7m4L_yavq<$=pTgOB&<{u>bI3~LlsQMDg+#JG|$N8R^b zlX~N=@+7R4zm?9sf9*k9!pjB8k?5t|TX9=~1U+d$r18DW9WaQkU zp?&@L^(Yz?4|GBtqxX2_H*oNW*Cvv`NfIh6F784c>d4jM;}F6m+Z2?D;)HD!&{~UMRAw19akI^Bm8U+M2IZP-KM=rd$>1}fdu}{ z@rIcYoaSMA<75pfQsb|~Z{GlF3+#YegP&jijoaw&C8=={ zzeszpBYu$_Pu>f#wH31V1Z0C0|I3q+zerx@UxD;VBXL=$emr@Ra(q9~1?(rpPv1eo z;$Kz0{NmRl0z!%KRU(F$2xR_#(A-2o=)c9!|AGVk$AC~`oyIS!?EXB+%zrm9lo(|B z^&kroe@zs(f06G;6t`a&w@xBt8hq7j-?v% zG?~))*BgYC9Xt{>aByLq?X2V;&?=)K$Q|gq`v2%in3GpD!5_XU4#pbms1a`xCxN&U zh~n^#J)y6+u!N!6Bc-fC_Q6N3gR~n;IY1~l)5g~&V~~3|)irVlL`peJxt8VecK~7x z-}2W;Hi?L^UqgfuYc;+fOSlw%a0k>>>Io!*0Cv`keL7!t19+YSbT!GLXoS&8xPsXC zu%BYdS*%dYRDNz|K1l9pW!l_=e5j<^!*rvaY$$9YXK~@Bpj}mE-1*{S^;oS#fhSM0 z*j@Ajk;FPr(gqhtV^YVt;2a)aItc+#e(E-OP+;}(sfQ=ZdmczhW$|sgO<|Rf?b4$t z#}1AQMUM$;*Gb7vh*Ls!Gjbj>z71SHUlPNTLLaNlVIx#uEx%TstCS00W3$}54#ysc z#JRes4a{BCl9*X!5a`r)J-#hDKz>mrUav0h;+-gxHsKoDuz}q0pr>QBAx!XoD@F7x zlQlLd9eXRxLs+m~Jim;v+Qb#TNE2rPDIkR&c9^z@Jy4ON~DBx}-K#a|ebHhRuqC@>S znxNj};qV1GqcWvwF6x5)M^(Aa_+%CNVhfkEo)@$ZDmWn;;kQ?&S)~K*T|*QFdI){v zz8rlni%$<_(Ixs;T|ci>5+|E_jbz?|Y^jth>fnf@$Ml0` zU_uDo0R^zZ2twHoio5PrS26bq+G2$A$8`%;IX4sQ-&!;?eP|kFF+tTPrJY}~79hOi z5WqjVz5}{7!kCYV&q9WHcx9(Ci;imB38{K_?dLM3!7Vh14>FK!2!-cNCvkS8-d8AO zn9s(GO>nKhPQysaB0J(vZ1rYC-O$QVN!ogFNR>3!ht+YE`gvjgo4khe-HXCwG*|44 zcJW<~+}+Qj-ZgalW}j9H&H#%<;g3{!pi#B523}TY7i^d^eI%<=GgR)}5^#!<*9)bT z+ZEYVb7B`g$r?N3N>1vw+VpXBt`;^p#nF>_D++NV(K0CNRO7X+RJoHbX~&L8iAjBw zcVQvBOUsVgi;`|w3LsEcVbY^3xYLFQ`I18mvYOMFx;1Ar5}XAzZ%CcmjEN^%zg;4i zK{o6B#PekS`^&5Rl`13D+Iq&$&h~Lk-n~Z>L>n~i_sCo(yVYChJmtzb$4Y`lq04%K zE-JmniO;hyy=ZaGD0P)>QYMuXIDfTf|jr-B~rl$iS9JrZpGpXm22~vo?e|3 znu7YAwuVD{QcsN)i5HNHk*whv>u{2okw+Nm>O|paiI4#{my1KEIo;zUYxs}S%g$eI zNy4^yep9b~OXvNOdw+-`mZ)lfP1O<$C;l{5OQX@4B>EZ)LsAancU_`Mw|}{61ZVq0It`i(83rib-UyilF)|8TX7bi?B+0xOYIW8 z-jrQ@VDAN6di$uG=gFpB?^N;Pp8~x;jPn%9u&LhT(LpyE8$5ikEU9*1o?l}M44M;^ zXrzoi|AsLZc`9XJoWPC6ZE=(+dV)Y&-X*V%qNm>tG^Rx0 z9f;TK(hw~R=L(y77Ze8k5o#R(q?@^p8BDdROE=T z6Iy+$adLxY&ieV5eVulsHL|j?ZZu-+C5+Apr_DaJaYMvR03&B7DWZJGNI61wY>_Rf z+aDxf19jZi#L1zfV$!|tRcB$OtyXfzk~UN;ie5!#XSZG)828F$6}e}@FX}KZ6r#6G zMh+Im9mNh}%IiiMssykGXRxZ-&Y)Q%v(`k5#G)iSplO85^30T$Vq@5iJI$;bZ)^^) zF|N|qEwRnru-+{JRIu6&@0lBydX(nGT&ALvJKJKz6~BJA8T^E?MNJw`>9IV%d2XIe z{x<)VZcvgOJ`JF#a)d<61|^`gbSiq61aU%=Y)lwdHTJ|t=WBv*b=S}GtlZBR*;6hW z<$jlBOLUBOKQ_8vk-4z9!Wfx}Xl%vuiF*<~ z0>hJzEZ@5WVxG~TPHgR5EPEX^VcEFrA%yQ8BU!}xDTgg%P9!++rso}bUleVKR9SBp z%pG;C(EH_*P{km>?(3&&OnELGCYL8)o4-1ENRJ|;PaFl_WER>1Ex-v8W;0noYbyY{ z-UBqYJwkHJh=n2}H?B$w3qRer=mN2a?{gAyjCIP(>|Lbm;$5v|6yZ8O!Pjy%O^p@i z5x##nwXdO-K{k{ct30mbH&@Sb1ReDxb2j0bnd9PlQ`5J+YE956Mx_}g4rNUAIN~;r zWlT;>k=1KT?Ntwy7p=Sde!_aaYqpEA^M}{F?MP5aN>I?=HlMyAkLZ0+U9@F!_;nS( z#&L5{idTEW)w~nuZN!9Ia}S8q(7xSll$44_4Z{X;`Uf<#3w=`cSuj$6M(q4)yy%C%7V(-MVEI$A=VuINFa;kM?OFp61#n48i zyef+tpKYDnfH`TV?%M1PnSZ;|@Zpk0=7}TToZxd_WBCA9Ar*?^s`i?i0md-!4 zk83xMSLdE^y}^ZwdXUrQuXq8gl?oLrLkDG{qJvr2v$E>E?G*|-oy-F3yUjII-8Hzx z^Om2T74do}OP_Wid|LoZTfK#t-yEB3Gp{T2Sg5amS!H`~K$R1*GyxVDi}gY!ZgHxk zY46A@jJw!0u<|@&Ps+{>30%#aJo%A*(Da_1G_=tjwAYiTd=Cg4eFhx|4<-oU^sr!L zp$@YqCN~J6`P3=U9UfGb59NMRSDjUR>47+3R6iMM#l31{1X+dP7{4I%I4rC}1L?{* zy+8X2AqJnFsmhx~_sTbMTW|o_ zLkd^WoSADaj0~!Rh6fbxWx>gfbB^;r*)zVdRLJ6DH*`<&(jJ{U9&WnFcePjqW3;zV zLoat!9fne36eGthA$nE941zF)w!r$wOrjcY2k1D5)Wf>+FEDZncnfZvOWax-555Cc zMM3ryJwihETX@-<7ANs%nU}B>ZQd<{mUf=nyj#+AU7mxA;-I4VI4s!uP?ew~+Dm-g zcQkkvu~$o;ewIJ=QE85AYO%+C75O!_K=%7rWb6*2I5T!Bith63wBDsW7AbAD1M1Su zf@6JA(bTwI80%)MHi<7E!mMg8?_d4)}>rcW5&Q!t3nSx^pf?rm)@$v`usld0)*V zX_IFX<>N{A0cNMWd6)xe#q-Jn(p%XJ5ZVT;ivbn*PH5Nd;?XTjH*4KLsRP{42~mH3 z^$Vr`(@?h`v80ydOC{|;E~zD!<^5t2{l~KZh=UdU+sB}qJ$_V{SfKOkm~kKid9=r6 zP4j?Nj|b$~xiIsG>C0DG84K=GgoxcIy<%t__l{zIfq`U`Dwoh|rT7{!n(kaKK-^Mf z?p$L(X4H{{GVPKSb;~%oAaucTayhY!F4*wm4ydAO7k(Dcj87IMa9cyc7@>RUupSF+ z?z!S^#;1<4B%sm@48?3i{`*ApWp6c~2kowm{X}VPDK}nRJxYnyMy6M{2d^s%bxP<+ z@jD6$72fF@z7#%bGx>mf#8xKe5$8vndN2DsE(qt*JvcM$EsVY&{fx9As;R&$u>+gP z#f0b=Y1w~NHy|qx`+-uVZSr`O-*F?Yr`uTOnx4tylviLgC zLL_!>+;#gJVDg=Cu0J}>KL9v^?VCbXJV1?`FrG80;;hhZf5B|cAKScdecep;zx}!m zAgi|+4PMUX`*QXoBu!O~!EpZ$fE7x85U)>mMed{34{^5?3Oem?*Bl zRV2SPjwr7G5pgBLk%{8^EiwG9_lV;99}!m~oS7)Dzf~l^HI68*{}FK|LL7P814;t=7f+}D?JT9n-7c(QMHn)L zAjtB5Ili(WKAbo$|F+c;kpF6Fhacc*JyKb;A0lors;$~+s5po22aT_LSBQ_U4 zt?H)&39uC)uKwwcUyUC?4Y#Z+4}h^<5nHB`J`2#zZ2@KoNri~5OB>8 zU4ojjy{yfjUI6;0ck0qx+2dirX7b8nh`2)$_g13H`J}Ijn)pXc<-fx~d0A>9AJNkF zl*e=2RGU^w6qni4b>IS!lcfKmRA4*b0cz?`PW{rA8PJ~cx&EBvJ_*@-D!%RaRJ>$s zE9)jeN}CoLz3mI6wEO3#`8GFx@lucjFpr1-kUjqqYO@16Iys8Z2blW8EhWEhJdpS` z%;3AZ=AWWv@oIkqqlapEqaPt9QKo9PBgP?6Rc20IiY3$jV)e=kbt2;=09+RG-rwiU zS4bdOaQ0;3`!#LTMcazlgY%u~_YcP!nY^-m;}pUYeaz{_1R69BKyd#aL*bX#a8P^( z09&ZQrhe+s7q$o8G&i&Za)N9MEAoCu9UQ$~Atu|ozvT;6A?g2Iqmi$eB`J2k14PhY zS)8Y!rU%-Pb8nPm8O_l~y9l?-_|)~Pv-SnlP*j4{T;)AQG~B3$VtLQ|M(S9+#@<|P zd*Co|ufMiY(fn|nF=TkS3yx11hip*;>$(7jQeu~6Z2f7w>Q3U_pEU0#&IWO95GCb@ zM)v=VEO3aU+L^GajY%Sv*yHGTA9eVgDaT-R&gWfxWk+T_8_AzvHJiOYp{Zz+5XW=I zW^yqlPFQ#TJ^Bb+T~Xp85h=vW!*AmETMDg44JFxDlv?CHO0(fQaBK^aig=CF*a0ac zaPiSN$J~@T_spm{vl|g>bhR->kdfW~{9YH2({G;@cIVzmSoflS^K{oedC>*W3#=(u zY??p3D3u3^@aMgVmy#Orcx`4T)YOgPN=kzp7)^gGyiA5!Sx*J5wUzPc&j3VT{yNTF z_g~lsCsqFjKcxJh>ss_xAP4+CU=9DuhQOcvxBnrZ1o-X{Fyw1HdIK^LP0(%+gM99g zot(Qbs^Fy906+k)UU+y;DY#SZPpP*5BbEC9%zH_8z5_JipS-C4R7d$w{@aNH^{q;k z-*Jy*=R3gb{mF}pC{QW>zgMt`8tN;dBiZ>55OqX>`rQlq_X@(l>U~6k`h`G!2beda zKoJG%pYc<^=dmO^-vKJ^dlaawb?ed|PAm&D?RHC>^7@eUgDm)Jb2**W_IjH!;nwIT z3#_)n;P0d#ZGH0%cROx{Jo(!=JaGeA?cWUm7E^>15)E5vP&3K!|ci+(C$Yqc!^Xs~8A7!m%-4H!6w88@2oxAI^XG z!wyI_xFnZ8sebA%AbB zC8vg=G`D9nC;mf1k;XNjJ<;3ZZ-Vb-lPlitrzBh_>DISsU$+LxI;W+9RA}c8C=%T7 z_o<=CC_!6;Ao1UDKdu@hb&sXO`F_vS=mgb+q3co4ZfqHAJ9|(s6nGj(bC*dEZ^A+c?=@E+&tp%#*#0BbMB1HZ{c0P+35GJnRZ$k74gah`{;LuK=w&P)&S z6D|x_ORd+fxGlh^Z!2V-QskR_9UC6e_vqBCG^0St)RfmSFE?x$h~YmQjWy;rm;IoW>T2#`k!lj z{1vv8mWU?&OR5~1C&F-gXWKQ>542BJ0Z6i}H7?@j6uulboo^}m4~?uJ7?J}lMgy7^ z59J@jBk0a5!XHD4hTlNu@R6J!@c_tmk$>xvo2)Q@2p(^wnSr;BElM-t`vY zb!#n|LjSZ_Lq-=9+d13EtLgj{dT*~$Hl@_KIiw`M3yqv-cB^ilbs*`{KdnWtGf1X_L#07GDXQIafGei1(<2 zEeqAbZiBZ@K|)J%3F;4Ww>Ba8q* zMwbtJWue%-%#pec3ifZ9;;q05hEe9>)475>pn{8KQCwk2n^3Z9{hI3sZTbU!f*15Q zFj)8MWyc$Cv(n)xc7{3^fuwWpP3-Fpi-tv6he!v{ki4TkH7QT!G2RkA5DklfO4=iR zZjJT7x!OORJ)j965W&rl^Imn2iQstRKo;m43M+u&j`O=lgpRu~R=uB8PxM?j2-RsV zR%vfuk;mDdx_V}$F$_;;S)*igFUqeFO`a6<5>h{C-H&+dI&aDOMhx5j4s@CDc1Y-H zaibglDd+KZ>-JSre|ekn3hA4Lz0s*&+6~&sTvipk%B}_5``*ms+=E=kQus?DK{fm< z$40Hr^&Rs;>F8F&>92?HfH<(Z8eIi=n5OQ6g3!vjAi4`ayKm^)9uuv&+ggu;-M{uU zzkxp+y9Cgx2XCd<&EY-AnIE}0Bj3p0k?xH+T2+vENUZW@rIGq!UiO1`si7#;Mo)$E zw#szEfMP;QJ9po$@yCPMe9=bw%Jr)%TqPwI{u-yRO!bgG!P;QhJ(dEhXwfv$sBFlo z_mYuL>k6k9b<9Qt)dyM@R+_?hxgJaG8lsMQqw<*F{$NdRryi+4g{zhGO7M78!nm9^ zgjy%lVTAm(zgM{WZXNOo=P{ju^SloGT_E)<*K<3!K9_s&KSX=t!sFrV-8&$4$?NZ1 zv2p~p7Ts;Y?oMU(mvzE*;FDn!Idh}ybHLV`XFTKU=it`?SvK}q+V%j7bxg8WXqjLW zmby5={?>}wTDlEX+)8BbfUHIdabyh{DPe@0kmt3Py2wk#ch&^WP`Vha0GAi0b*^sS zl5g6NDpWAN$}bv@NZnVXeC)Y%3;(omfLYM3G%ue9<`l`YzQHpkqKy(Nn)JPl`}(Qx zj@aB~(VV_r6%dGIjtsb`#b12=$$U}%$TnEKevSK3RmyFba&EhBV@Inw=PT0HtQ>(T zxn_C$r&#whL8Emqx_IJTu9J-pAGZuLxH`cl%4B3G&*9IZ=Hd+7lOqYE8FrScBE8*S zFZ-lfs#7^DD^O)H?P0*%qer3)=|~#6P#~kqJ7&JP6)Scsdsg`Ehz+Kjw%Sg8^pfk{ zuTBQjsN8yzhOwl%^=#(&xOK3Y##p3P|5)MC<7tTo?EWjy<%CE=c3;tk)_Yx8gFHKb zZAiAI9 zz!<&4budYx$tF(pHR)EP>UOuxsg7JeKBQ1hhR%JvY@%*bcJ+Q@xt7Ge_vM%8vxo5E zikZA)FV2XbX)b!?d@^VL{eW+@!264x$et^l9b8E+CuEjcr}EkoC14(6h6Bulv^es9{az)C5Y{3@?Fa9I?rI5ivIbG%$M(1hafJ{QVUD zzIH_xVP6>?4k4Ec0ly>?urhAZeupfx-@{Ehw4}(dHDigtt^mba|8F1Wr7{mfKMM%X3WVwrLorssoKw3hKnmj*LxHyn<^9U~G%)HI6i1plO8OgLk zgda)0tqrFu0jzxSiG71J)Ml=;lb4$Nu$3H@W zloHDEQP-E)T6HuqC)@RU`6J~$ z@z#=)gLi}~lFw5P$r>khTAq-%$S{mFxl;c4!90T~!!z|~^V<%Dm0=+Qw?ktcb7ZnI zPiRKCoDN49<#X?SMlq*1#I&dOQwh`?urwXoK&7DjqF3`Wu^NW&q2`h=WvP=~UHXN% zoii)?A81q$oaus#y9M+`7`I6nmurNJ>Sw%=ljF*MVW#NZFWHCg*qj|=33wuN*4Wr( zWTw*Q?fVJ1Zlh(R%)a@$Ql2sdsdGFB3&t;DocfFmcX9W}17d2C^Lq5jS5Qkfiv2mK z!q6hv(6gDWuZAW1Ui568He!{`JQcAX>$oLpGjbRkiELqW#2KddH#+B5zc!g+a?=Qr z81xpiEfM3m^l;XBl$3q5O1 z8##Pot8@0)(4KVtLNAx+iAx?+`7_S^rY6e{S3fd6k-eYtB)zIEtw?LNXfAuuv;1|dZI_(GO}91rFktd{-h4yZkya1ut~^Ov3Fj{(}L$f@pt;JP>J|* z4&DKUCDW9JO~8;e9Xp^Yz{@%c*#R+X;EoJ{aa*tnAaFIFL6(zJ3dX7yKsHwa2vPJ7 zs2&J{Q{D*P0V%>a>3;YU8GrCgP-mMP6?SFYCfc)A%N>A-OP?oKMz&}PTsJp&4C*uF zidJbg2WK1Sqel`h@g|P+>-VM7n?yg?$_WAOrf>q8;g;~vB=!!=jSFlI#lT@nwhZi_#0UIh4*0Uf$@OEsKps2@bqEq(#Rlu3 z*a7k6K(Gt0SlHOcZK&MMge{{;#tO{imr+aN$JeYy;S@tg_o3X4GTdih(l38>U7WOj z80X4*ZF2Wa*CSt{l!Q^BzMjVk$JucOCyt&v*_qqX=)UjF@{!qWfyg5Ui_+)&QoHq; zBq%E>7-sRK6oHX@L{h0!Vy!|=2=0wG+#$L0CpYf7Y!zQk3FA+j{Kp__U~T$)q=SvG$0_VV9R{%RRDO4(>`a#?5t5t~egE7J` z)-5Ikuyfd34;&ptUOs>|sE^TB40IEI!jMPZ?##Il()>Q=6%}YwlZ))0wQc%>DVpW3 zIQITiPHvsJj~adZW43xE%joZQK_i#`nt_{4&4R9?s@B;fyHkKTK(`XPhM*y7> zCLjk_?X;GM)fwSPcR){50rSokhOGzQhX5g_f&HnOZImFYc6;i_r~UL*4Vj@232c)9|D7+b8Wi*O%U^#3roF^3Mw~HG z;u<4LC2_kTZm>j^^b-|I)Rlj;IleX{{xs{N3IBpX3hU?uqG8eq+{IEjqu&Pz)#?)| z(+Y9<0sQ*tu*zNSD}m7)BeoVKqa@LVOl0G*0pBj`D8ezX48-WotHQfJm6?4-+gYv}E=!?LqMOKMB9 zrx-3#KCx$cdU<;9Lq8o39VhSW-oR)CPc%=Ve3^V1=|}5(8u!eSEIBMm+=ZJ{o3nL= zqJ{iR6DB$*deaj$5|k`j{`NGXOPdnjl9`j8lO4>&2NS2_hc)&GRz*6cv-aC`?{j-T z-mEiQJ`)`~O z2S_7R;=@2XDa6Bn=@dllG2;bQ|Bs{9zM$L4h!r(|6WxCmZxQi1zn?_yKQ(ud@2(!C zDfK9@5{ds4XW*|k1OK_*0`k3Jw2w>g(dhvln9*rt&?EV(Wd`y3FEl6G_q5bN@`t*5 zt}l!ffM$=29e4O*n*F%!|mJqYO}E8oTk z#2}t`n|T}djO1D*qtCqc0^$DW_xP8phgJSCP_dpcI-_Kfs%G_hAowECLvS@&NI&JL zPiN-sG_LwIP~-C>_uhBN8vQ&l_46~yzw;00%A71cJ;lgQwr2z0e~+LY90cH|R(3#| zA9Hu-dgC8LCQ7_q38RqJC?^M9o3)%U-Yk(lywC5=D3K@xN`>+M_%oiqrLC}MuBG&A;d~Zj$lN0|!H`_noluIPoz&BF zxLrB5ZVM!Skx0Zg6sU5L$*Rd3f!XP93UROjr4sFU&cwt6AMnm8VUCJ%b|76Rmmk%w z<{4g|he~_2(o!Ckclonx#hiZUkW8`2aD|~YOpKRgJCH3<{AffN$PcNGJpIW=1()cT z7>MyU5eE^cfVc{Xg79zK3pN=F*%?TtUllTu{)?_@ce;Lkv(HJb9pR9jL@Bg*OECqsmfU{~N_}kKgWBp7w$uo$P`S?E zpdGjJQm8S(jc!6LNjzE~{>D~M!g*HO*iX85Vbzxd!q+f5aZ8p@y@G`eO$f+6hq20Y zbh(^#pu-%$yMwT<-0SEQ>*EizdQ767F))nfG%xOz@RlEBi%z1L&1Ji0<65`HQF);L zroyxLuf2*@z|+$98+lQ$-rl?|M+&@)PSc)DjlqEH*D_9TOLssPqruA=d_M5CHY|+q zcECx-B}o1;Tmmi7+-z`)5YuKwZH3teh<%$~(WCe(*vz4xj-deWUZA*$%sW z_MCM)olJW7@!119$z<6_PNWIW=(J~pP83Q@bdB7<1K7Sz8O3{~_ka=rwGw_c^=dNJ zHD2ON#F-$j38E-`ADcpa0?*UkPf9v=Rd@9$1)QN^AmMd2^EgT4SUv8~MZrKQ1e@u( z0qzRm=BEprx$uqwo7%sLNDBbw{1%6U%nwXwt&yUI+&n9@U|D?Z0hPm}_mrIAT$q7Y zs#nKP)t{8=>59Cys_^=CVMOk$-gHF?)DhFV`oT{9a! zQhLWyK-+`lJlHY|^vH_!%O0r_FNkwMTnFEh1%q3w88dTT{v2$*Nz`g*Y3`Ho_;lB_ usmmJlWdqS=gIU?T*OMv82A-T|cU=A4kOS?m{kQY4y3G91h8-k3{r?AN37K~Q literal 0 HcmV?d00001 diff --git a/doc/user_cn_guide.md b/docs/user_cn_guide.md similarity index 100% rename from doc/user_cn_guide.md rename to docs/user_cn_guide.md diff --git a/kafka-manager-common/pom.xml b/kafka-manager-common/pom.xml new file mode 100644 index 00000000..2782e5eb --- /dev/null +++ b/kafka-manager-common/pom.xml @@ -0,0 +1,105 @@ + + + 4.0.0 + com.xiaojukeji.kafka + kafka-manager-common + 2.0.0-SNAPSHOT + jar + + + kafka-manager + com.xiaojukeji.kafka + 2.0.0-SNAPSHOT + + + + 1.0.0-SNAPSHOT + true + true + 1.8 + 1.8 + UTF-8 + UTF-8 + + + + + org.apache.httpcomponents + httpcore + + + org.apache.httpcomponents + httpclient + + + commons-httpclient + commons-httpclient + + + org.apache.httpcomponents + httpmime + + + + commons-beanutils + commons-beanutils + 1.9.3 + + + org.apache.curator + curator-recipes + 2.10.0 + + + org.apache.zookeeper + zookeeper + + + com.alibaba + fastjson + + + org.apache.kafka + kafka_2.10 + + + commons-lang + commons-lang + + + + io.springfox + springfox-swagger2 + + + io.springfox + springfox-swagger-ui + + + io.swagger + swagger-annotations + 1.5.13 + + + org.springframework + spring-web + 5.0.9.RELEASE + compile + + + com.fasterxml.jackson.core + jackson-databind + 2.9.7 + + + org.apache.commons + commons-pool2 + + + javax.servlet + javax.servlet-api + + + \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/annotations/ApiLevel.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/annotations/ApiLevel.java new file mode 100644 index 00000000..1a3e91d7 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/annotations/ApiLevel.java @@ -0,0 +1,24 @@ +package com.xiaojukeji.kafka.manager.common.annotations; + +import com.xiaojukeji.kafka.manager.common.constant.ApiLevelContent; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 接口分级限流 + * @author zengqiao + * @date 2020-07-20 + */ +@Target(ElementType.METHOD) +@Retention(RUNTIME) +@Documented +public @interface ApiLevel { + int level() default ApiLevelContent.LEVEL_DEFAULT_4; + + int rateLimit() default Integer.MAX_VALUE; +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/AccountRoleEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/AccountRoleEnum.java new file mode 100644 index 00000000..9c3cc06c --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/AccountRoleEnum.java @@ -0,0 +1,50 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * 用户角色 + * @author zengqiao_cn@163.com + * @date 19/4/15 + */ +public enum AccountRoleEnum { + UNKNOWN(-1, "unknown"), + + NORMAL(0, "normal"), + + RD(1, "rd"), + + OP(2, "op"); + + private Integer role; + + private String message; + + AccountRoleEnum(Integer role, String message) { + this.role = role; + this.message = message; + } + + public Integer getRole() { + return role; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return "AccountRoleEnum{" + + "role=" + role + + ", message='" + message + '\'' + + '}'; + } + + public static AccountRoleEnum getUserRoleEnum(Integer role) { + for (AccountRoleEnum elem: AccountRoleEnum.values()) { + if (elem.role.equals(role)) { + return elem; + } + } + return AccountRoleEnum.UNKNOWN; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ApiLevelEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ApiLevelEnum.java new file mode 100644 index 00000000..73be0d16 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ApiLevelEnum.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author zengqiao + * @date 20/7/27 + */ +public enum ApiLevelEnum { + LEVEL_0(0), + LEVEL_1(1), + LEVEL_2(2), + LEVEL_3(3) + ; + + private int level; + + ApiLevelEnum(int level) { + this.level = level; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ClusterComboEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ClusterComboEnum.java new file mode 100644 index 00000000..06f6b91b --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ClusterComboEnum.java @@ -0,0 +1,37 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author zengqiao + * @date 20/4/21 + */ +public enum ClusterComboEnum { + BYTES_IN_200(200*1024*1024, "200MB/s"), + BYTES_IN_400(400*1024*1024, "400MB/s"), + BYTES_IN_600(600*1024*1024, "600MB/s"), + ; + + private Integer code; + + private String message; + + ClusterComboEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return "ClusterComboEnum{" + + "code=" + code + + ", message='" + message + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ClusterModeEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ClusterModeEnum.java new file mode 100644 index 00000000..199cc7cd --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ClusterModeEnum.java @@ -0,0 +1,48 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * 集群模式 + * @author zengqiao + * @date 20/4/1 + */ +public enum ClusterModeEnum { + /** + * 共享模式 + */ + SHARED_MODE(0, "共享集群"), + + /** + * 独享模式 + */ + EXCLUSIVE_MODE(1, "独享集群"), + + /** + * 独立模式 + */ + INDEPENDENT_MODE(2, "独立集群"); + + private Integer code; + + private String message; + + ClusterModeEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return "ClusterModeEnum{" + + "code=" + code + + ", message='" + message + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/DBStatusEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/DBStatusEnum.java new file mode 100644 index 00000000..4f6fb1cf --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/DBStatusEnum.java @@ -0,0 +1,25 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author zengqiao + * @date 20/6/4 + */ +public enum DBStatusEnum { + DEAD(-1), + ALIVE(0) + ; + + private int status; + + DBStatusEnum(int status) { + this.status = status; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/IDCEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/IDCEnum.java new file mode 100644 index 00000000..0c4c877a --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/IDCEnum.java @@ -0,0 +1,45 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author zengqiao + * @date 20/5/26 + */ +public enum IDCEnum { + CN("cn", "国内"), + US("us", "美东"), + RU("ru", "俄罗斯"), + ; + + private String idc; + + private String name; + + IDCEnum(String idc, String name) { + this.idc = idc; + this.name = name; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "IDCEnum{" + + "idc='" + idc + '\'' + + ", name='" + name + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaBrokerRoleEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaBrokerRoleEnum.java new file mode 100644 index 00000000..befd5257 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaBrokerRoleEnum.java @@ -0,0 +1,34 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author zengqiao + * @date 20/5/20 + */ +public enum KafkaBrokerRoleEnum { + NORMAL("NormalBroker"), + + COORDINATOR("Coordinator"), + + CONTROLLER("Controller"), + ; + private String role; + + KafkaBrokerRoleEnum(String role) { + this.role = role; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + @Override + public String toString() { + return "KafkaBrokerRoleEnum{" + + "role='" + role + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaClientEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaClientEnum.java new file mode 100644 index 00000000..6e5bea6f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaClientEnum.java @@ -0,0 +1,46 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author zengqiao + * @date 20/5/29 + */ +public enum KafkaClientEnum { + PRODUCE_CLIENT(0, "Produce"), + + FETCH_CLIENT(1, "Fetch"), + + ; + + private Integer code; + + private String name; + + KafkaClientEnum(Integer code, String name) { + this.code = code; + this.name = name; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "KafkaClientEnum{" + + "code=" + code + + ", name='" + name + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaFileEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaFileEnum.java new file mode 100644 index 00000000..f1196f91 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/KafkaFileEnum.java @@ -0,0 +1,54 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author zengqiao + * @date 20/4/26 + */ +public enum KafkaFileEnum { + PACKAGE(0, "Kafka压缩包", ".tgz"), + + SERVER_CONFIG(1, "KafkaServer配置", ".properties"), + ; + + private Integer code; + + private String message; + + private String suffix; + + KafkaFileEnum(Integer code, String message, String suffix) { + this.code = code; + this.message = message; + this.suffix = suffix; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } + + public String getSuffix() { + return suffix; + } + + @Override + public String toString() { + return "KafkaFileEnum{" + + "code=" + code + + ", message='" + message + '\'' + + ", suffix=" + suffix + + '}'; + } + + public static KafkaFileEnum getByCode(Integer code) { + for (KafkaFileEnum elem: KafkaFileEnum.values()) { + if (elem.getCode().equals(code)) { + return elem; + } + } + return null; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ModuleEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ModuleEnum.java new file mode 100644 index 00000000..ac2a8947 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/ModuleEnum.java @@ -0,0 +1,76 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +import com.google.common.collect.Maps; + +import java.util.Map; + +/** + * @author zhongyuankai_i + * @date 20/09/03 + */ +public enum ModuleEnum { + TOPIC(0, "Topic"), + + APP(1, "应用"), + + QUOTA(2, "配额"), + + AUTHORITY(3, "权限"), + + CLUSTER(4, "集群"), + + PARTITION(5, "分区"), + + UNKNOWN(-1, "未知") + ; + ModuleEnum(int code, String message) { + this.code = code; + this.message = message; + } + + private int code; + + private String message; + + public int getCode() { + return code; + } + + public String getMessage() { + return message; + } + + public Map toMap() { + Map map = Maps.newHashMap(); + map.put("code", code); + map.put("message", message); + return map; + } + + public static ModuleEnum valueOf(Integer code) { + if (code == null) { + return ModuleEnum.UNKNOWN; + } + for (ModuleEnum state : ModuleEnum.values()) { + if (state.getCode() == code) { + return state; + } + } + + return ModuleEnum.UNKNOWN; + } + + public static boolean validate(Integer code) { + if (code == null) { + return false; + } + for (ModuleEnum state : ModuleEnum.values()) { + if (state.getCode() == code) { + return true; + } + } + + return false; + } + +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OffsetLocationEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OffsetLocationEnum.java new file mode 100644 index 00000000..aeeff95d --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OffsetLocationEnum.java @@ -0,0 +1,36 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author limeng + * @date 2017/11/21 + */ +public enum OffsetLocationEnum { + /** + * 存储于zk + */ + ZOOKEEPER("zookeeper"), + + /** + * 存储于broker + */ + BROKER("broker"); + + public final String location; + + OffsetLocationEnum(String location) { + this.location = location; + } + + public static OffsetLocationEnum getOffsetStoreLocation(String location) { + if (location == null) { + return null; + } + + for (OffsetLocationEnum offsetStoreLocation: OffsetLocationEnum.values()) { + if (offsetStoreLocation.location.equals(location)) { + return offsetStoreLocation; + } + } + return null; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OffsetPosEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OffsetPosEnum.java new file mode 100644 index 00000000..7f5deea2 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OffsetPosEnum.java @@ -0,0 +1,42 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * offset获取的位置 + * @author zengqiao + * @date 19/5/29 + */ +public enum OffsetPosEnum { + NONE(0), + + BEGINNING(1), + + END(2), + + BOTH(3); + + public final Integer code; + + OffsetPosEnum(Integer code) { + this.code = code; + } + + public Integer getCode() { + return code; + } + + public static OffsetPosEnum getOffsetPosEnum(Integer code) { + for (OffsetPosEnum offsetPosEnum : values()) { + if (offsetPosEnum.getCode().equals(code)) { + return offsetPosEnum; + } + } + return NONE; + } + + @Override + public String toString() { + return "OffsetPosEnum{" + + "code=" + code + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OperateEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OperateEnum.java new file mode 100644 index 00000000..2bc874ec --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OperateEnum.java @@ -0,0 +1,59 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author zhongyuankai + * @date 20/09/03 + */ +public enum OperateEnum { + ADD(0, "新增"), + + DELETE(1, "删除"), + + EDIT(2, "修改"), + + UNKNOWN(-1, "unknown"), + ; + + OperateEnum(int code, String message) { + this.code = code; + this.message = message; + } + + private int code; + + private String message; + + public int getCode() { + return code; + } + + public String getMessage() { + return message; + } + + public static OperateEnum valueOf(Integer code) { + if (code == null) { + return OperateEnum.UNKNOWN; + } + for (OperateEnum state : OperateEnum.values()) { + if (state.getCode() == code) { + return state; + } + } + + return OperateEnum.UNKNOWN; + } + + public static boolean validate(Integer code) { + if (code == null) { + return false; + } + for (OperateEnum state : OperateEnum.values()) { + if (state.getCode() == code) { + return true; + } + } + + return false; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OperationStatusEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OperationStatusEnum.java new file mode 100644 index 00000000..cf8f53d2 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/OperationStatusEnum.java @@ -0,0 +1,30 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * 操作状态类型 + * @author zengqiao + * @date 19/11/21 + */ +public enum OperationStatusEnum { + CREATE(0, "创建"), + UPDATE(1, "更新"), + DELETE(2, "删除"), + ; + + private Integer code; + + private String message; + + OperationStatusEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/PeakFlowStatusEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/PeakFlowStatusEnum.java new file mode 100644 index 00000000..9b71f038 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/PeakFlowStatusEnum.java @@ -0,0 +1,50 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * 峰值状态枚举 + * @author zengqiao + * @date 20/5/11 + */ +public enum PeakFlowStatusEnum { + BETWEEN_ALL(0, "全部"), + BETWEEN_00_60(1, "使用率0%-60%"), + BETWEEN_60_80(2, "使用率60%-80%"), + BETWEEN_80_100(3, "使用率80%-100%"), + BETWEEN_100_PLUS(4, "使用率大于100%"), + BETWEEN_EXCEPTION(5, "数据获取失败"), + + ; + + public Integer code; + + public String message; + + PeakFlowStatusEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return "PeakFlowStatusEnum{" + + "code=" + code + + ", message='" + message + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/RebalanceDimensionEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/RebalanceDimensionEnum.java new file mode 100644 index 00000000..6659f904 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/RebalanceDimensionEnum.java @@ -0,0 +1,31 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * 优先副本选举维度 + * @author zengqiao + * @date 20/4/23 + */ +public enum RebalanceDimensionEnum { + CLUSTER(0, "Cluster维度"), + REGION(1, "Region维度"), + BROKER(2, "Broker维度"), + TOPIC(3, "Topic维度"), + ; + + private Integer code; + + private String message; + + RebalanceDimensionEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/SinkMonitorSystemEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/SinkMonitorSystemEnum.java new file mode 100644 index 00000000..b843a90c --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/SinkMonitorSystemEnum.java @@ -0,0 +1,45 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * 是否上报监控系统 + * @author zengqiao + * @date 20/9/25 + */ +public enum SinkMonitorSystemEnum { + SINK_MONITOR_SYSTEM(0, "上报监控系统"), + NOT_SINK_MONITOR_SYSTEM(1, "不上报监控系统"), + ; + + private Integer code; + + private String message; + + SinkMonitorSystemEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return "SinkMonitorSystemEnum{" + + "code=" + code + + ", message='" + message + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TaskStatusEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TaskStatusEnum.java new file mode 100644 index 00000000..ebf3dc82 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TaskStatusEnum.java @@ -0,0 +1,72 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * 任务状态 + * @author zengqiao + * @date 2017/6/29. + */ +public enum TaskStatusEnum { + UNKNOWN( -1, "未知"), + + NEW( 0, "新建"), + + RUNNABLE( 20, "就绪"), + WAITING( 21, "等待"), + + RUNNING( 30, "运行中"), + KILLING( 31, "杀死中"), + + BLOCKED( 40, "暂停"), + + UNFINISHED( 99, "未完成"), + FINISHED( 100, "完成"), + + SUCCEED( 101, "成功"), + FAILED( 102, "失败"), + CANCELED( 103, "取消"), + IGNORED( 104, "忽略"), + TIMEOUT( 105, "超时"), + KILL_FAILED(106, "杀死失败"), + + ; + + private Integer code; + + private String message; + + TaskStatusEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return "TaskStatusEnum{" + + "code=" + code + + ", message='" + message + '\'' + + '}'; + } + + public static Boolean isFinished(Integer code) { + if (code >= FINISHED.getCode()) { + return true; + } + return false; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TaskStatusReassignEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TaskStatusReassignEnum.java new file mode 100644 index 00000000..7fd6ef8f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TaskStatusReassignEnum.java @@ -0,0 +1,55 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author zengqiao + * @date 20/6/11 + */ +public enum TaskStatusReassignEnum { + UNKNOWN(TaskStatusEnum.UNKNOWN), + + NEW(TaskStatusEnum.NEW), + + RUNNABLE(TaskStatusEnum.RUNNABLE), + + RUNNING(TaskStatusEnum.RUNNING), + +// FINISHED(TaskStatusEnum.FINISHED), + SUCCEED(TaskStatusEnum.SUCCEED), + FAILED(TaskStatusEnum.FAILED), + CANCELED(TaskStatusEnum.CANCELED), + ; + + private Integer code; + + private String message; + + TaskStatusReassignEnum(TaskStatusEnum taskStatusEnum) { + this.code = taskStatusEnum.getCode(); + this.message = taskStatusEnum.getMessage(); + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return "TaskStatusReassignEnum{" + + "code=" + code + + ", message='" + message + '\'' + + '}'; + } + + public static Boolean isFinished(Integer code) { + if (SUCCEED.getCode().equals(code) + || FAILED.getCode().equals(code) + || CANCELED.getCode().equals(code)) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicAuthorityEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicAuthorityEnum.java new file mode 100644 index 00000000..2cfba027 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicAuthorityEnum.java @@ -0,0 +1,36 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * topic权限 + * @author zhongyuankai + * @date 20/4/29 + */ +public enum TopicAuthorityEnum { + DENY(0, "无"), + + READ(1, "只读"), + + WRITE(2, "只写"), + + READ_WRITE(3, "可读可写"), + + OWNER(4, "可管理"), + ; + + private Integer code; + + private String message; + + TopicAuthorityEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicOffsetChangedEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicOffsetChangedEnum.java new file mode 100644 index 00000000..ecb6b2f1 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicOffsetChangedEnum.java @@ -0,0 +1,45 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * @author zengqiao + * @date 20/8/24 + */ +public enum TopicOffsetChangedEnum { + UNKNOWN(-1, "unknown"), + NO(0, "no"), + YES(1, "yes"), + ; + + private Integer code; + + private String message; + + TopicOffsetChangedEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return "TopicOffsetChangedEnum{" + + "code=" + code + + ", message='" + message + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicReassignActionEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicReassignActionEnum.java new file mode 100644 index 00000000..2c4361c6 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/TopicReassignActionEnum.java @@ -0,0 +1,39 @@ +package com.xiaojukeji.kafka.manager.common.bizenum; + +/** + * Topic迁移动作 + * @author zengqiao + * @date 20/4/16 + */ +public enum TopicReassignActionEnum { + START("start"), + MODIFY("modify"), + CANCEL("cancel"), + ; + + private String action; + + TopicReassignActionEnum(String action) { + this.action = action; + } + + public String getAction() { + return action; + } + + @Override + public String toString() { + return "TopicReassignActionEnum{" + + "action='" + action + '\'' + + '}'; + } + + public static TopicReassignActionEnum getByAction(String action) { + for (TopicReassignActionEnum elem: TopicReassignActionEnum.values()) { + if (elem.action.equals(action)) { + return elem; + } + } + return null; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/gateway/GatewayConfigKeyEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/gateway/GatewayConfigKeyEnum.java new file mode 100644 index 00000000..667be791 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/bizenum/gateway/GatewayConfigKeyEnum.java @@ -0,0 +1,48 @@ +package com.xiaojukeji.kafka.manager.common.bizenum.gateway; + +/** + * @author zengqiao + * @date 20/7/28 + */ +public enum GatewayConfigKeyEnum { + SD_CLUSTER_ID("SERVICE_DISCOVERY_CLUSTER_ID", "SERVICE_DISCOVERY_CLUSTER_ID"), + SD_QUEUE_SIZE("SERVICE_DISCOVERY_QUEUE_SIZE", "SERVICE_DISCOVERY_QUEUE_SIZE"), + SD_APP_ID_RATE("SERVICE_DISCOVERY_APPID_RATE", "SERVICE_DISCOVERY_APPID_RATE"), + SD_IP_RATE("SERVICE_DISCOVERY_IP_RATE", "SERVICE_DISCOVERY_IP_RATE"), + SD_SP_RATE("SERVICE_DISCOVERY_SP_RATE", "SERVICE_DISCOVERY_SP_RATE"), + + ; + + private String configType; + + private String configName; + + GatewayConfigKeyEnum(String configType, String configName) { + this.configType = configType; + this.configName = configName; + } + + public String getConfigType() { + return configType; + } + + public void setConfigType(String configType) { + this.configType = configType; + } + + public String getConfigName() { + return configName; + } + + public void setConfigName(String configName) { + this.configName = configName; + } + + @Override + public String toString() { + return "GatewayConfigKeyEnum{" + + "configType='" + configType + '\'' + + ", configName='" + configName + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ApiLevelContent.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ApiLevelContent.java new file mode 100644 index 00000000..2447564f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ApiLevelContent.java @@ -0,0 +1,15 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +/** + * @author zengqiao + * @date 20/7/28 + */ +public class ApiLevelContent { + public static final int LEVEL_VIP_1 = 1; + + public static final int LEVEL_IMPORTANT_2 = 2; + + public static final int LEVEL_NORMAL_3 = 3; + + public static final int LEVEL_DEFAULT_4 = 4; +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ApiPrefix.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ApiPrefix.java new file mode 100644 index 00000000..5cd1ab5b --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ApiPrefix.java @@ -0,0 +1,26 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +/** + * Api前缀 + * @author zengqiao + * @date 20/4/16 + */ +public class ApiPrefix { + public static final String API_V1_SSO_PREFIX = "/api/v1/sso/"; + + public static final String API_V1_NORMAL_PREFIX = "/api/v1/normal/"; + + public static final String API_V1_RD_PREFIX = "/api/v1/rd/"; + + public static final String API_V1_OP_PREFIX = "/api/v1/op/"; + + public static final String API_V1_THIRD_PART_PREFIX = "/api/v1/third-part/"; + + public static final String API_V2_THIRD_PART_PREFIX = "/api/v2/third-part/"; + + public static final String API_V1_OBSOLETE_PREFIX = "/api/v1/"; + + public static final String API_V2_OBSOLETE_PREFIX = "/api/v2/"; + + public static final String GATEWAY_API_V1_PREFIX = "/gateway/api/v1/"; +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ConfigConstant.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ConfigConstant.java new file mode 100644 index 00000000..faca17b0 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/ConfigConstant.java @@ -0,0 +1,33 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +/** + * 配置的常量KEY + * @author zengqiao + * @date 20/7/1 + */ +public class ConfigConstant { + /** + * 专家服务 + */ + public static final String REGION_HOT_TOPIC_CONFIG_KEY = "REGION_HOT_TOPIC_CONFIG"; + public static final String TOPIC_INSUFFICIENT_PARTITION_CONFIG_KEY = "TOPIC_INSUFFICIENT_PARTITION_CONFIG"; + public static final String EXPIRED_TOPIC_CONFIG_KEY = "EXPIRED_TOPIC_CONFIG"; + + /** + * + */ + public static final String PRODUCE_CONSUMER_METRICS_CONFIG_KEY = "PRODUCE_CONSUMER_METRICS_CONFIG_KEY"; + + public static final String PRODUCE_TOPIC_METRICS_CONFIG_KEY = "PRODUCE_TOPIC_METRICS_CONFIG_KEY"; + + public static final long MAX_LIMIT_NUM = 200L; + + /** + * broker 默认最大峰值流量 100M + */ + public static final Long DEFAULT_BROKER_CAPACITY_LIMIT = 100 * 1024 * 1024L; + + public static final String BROKER_CAPACITY_LIMIT_CONFIG_KEY = "BROKER_CAPACITY_LIMIT_CONFIG"; + + public static final String KAFKA_CLUSTER_DO_CONFIG_KEY = "KAFKA_CLUSTER_DO_CONFIG"; +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/Constant.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/Constant.java new file mode 100644 index 00000000..81c1dc89 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/Constant.java @@ -0,0 +1,48 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +/** + * @author zengqiao + * @date 20/2/28 + */ +public class Constant { + public static final Integer SUCCESS = 0; + + public static final Integer MAX_AVG_BYTES_DURATION = 10; + + public static final Integer BATCH_INSERT_SIZE = 50; + + public static final Integer DEFAULT_SESSION_TIMEOUT_UNIT_MS = 30000; + + public static final Integer MAX_TOPIC_OPERATION_SIZE_PER_REQUEST = 10; + + /** + * 不进行过滤的BrokerId + */ + public static final Integer NOT_FILTER_BROKER_ID = -1; + + /** + * 默认最近20分钟的连接信息 + */ + public static final Long TOPIC_CONNECTION_LATEST_TIME_MS = 20 * 60 * 1000L; + + /** + * 工单相关 + */ + public static final String HANDLE_APP_APPLY_MAX_NUM = "handle_app_apply_order_num"; + + public static final Integer HANDLE_APP_APPLY_MAX_NUM_DEFAULT = 10; + + public static final String AUTO_HANDLE_USER_NAME = "auto_handle"; + + public static final String AUTO_HANDLE_CHINESE_NAME = "自动审批"; + + public static final String UNKNOWN_VERSION = "unknownVersion"; + + public static final String UNKNOWN_USER = "UNKNOWN_USER"; + + public static final String DEFAULT_USER_NAME = "kafka-admin"; + + public static final Integer DEFAULT_MAX_CAL_TOPIC_EXPIRED_DAY = 90; + + public static final Integer INVALID_CODE = -1; +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/KafkaConstant.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/KafkaConstant.java new file mode 100644 index 00000000..b8c5ef19 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/KafkaConstant.java @@ -0,0 +1,17 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +/** + * @author zengqiao + * @date 20/5/20 + */ +public class KafkaConstant { + public static final String COORDINATOR_TOPIC_NAME = "__consumer_offsets"; + + public static final String BROKER_HOST_NAME_SUFFIX = ".diditaxi.com"; + + public static final String CLIENT_VERSION_CODE_UNKNOWN = "-1"; + + public static final String CLIENT_VERSION_NAME_UNKNOWN = "unknown"; + + public static final String RETENTION_MS_KEY = "retention.ms"; +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/KafkaMetricsCollections.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/KafkaMetricsCollections.java new file mode 100644 index 00000000..9c7f59e3 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/KafkaMetricsCollections.java @@ -0,0 +1,42 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +/** + * + * @author zengqiao + * @date 20/4/22 + */ +public class KafkaMetricsCollections { + public static final int COMMON_DETAIL_METRICS = 0; + + /** + * Broker流量详情 + */ + public static final int BROKER_TO_DB_METRICS = 101; // Broker入DB的Metrics指标 + public static final int BROKER_OVERVIEW_PAGE_METRICS = 103; // Broker状态概览的指标 + public static final int BROKER_ANALYSIS_METRICS = 105; // Broker分析的指标 + public static final int BROKER_TOPIC_ANALYSIS_METRICS = 106; // Broker分析的指标 + public static final int BROKER_BASIC_PAGE_METRICS = 107; // Broker基本信息页面的指标 + public static final int BROKER_STATUS_PAGE_METRICS = 108; // Broker状态 + public static final int BROKER_HEALTH_SCORE_METRICS = 109; // Broker健康分 + + /** + * Topic流量详情 + */ + public static final int TOPIC_FLOW_OVERVIEW = 201; + public static final int TOPIC_METRICS_TO_DB = 202; + public static final int TOPIC_REQUEST_TIME_METRICS_TO_DB = 203; + public static final int TOPIC_BASIC_PAGE_METRICS = 204; + public static final int TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS = 205; + public static final int TOPIC_THROTTLED_METRICS_TO_DB = 206; + + + /** + * App+Topic流量详情 + */ + public static final int APP_TOPIC_METRICS_TO_DB = 300; + + /** + * Broker信息 + */ + public static final int BROKER_VERSION = 400; +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/LogConstant.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/LogConstant.java new file mode 100644 index 00000000..55fa756f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/LogConstant.java @@ -0,0 +1,13 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +/** + * @author zengqiao + * @date 20/8/10 + */ +public class LogConstant { + public static final String COLLECTOR_METRICS_LOGGER = "COLLECTOR_METRICS_LOGGER"; + + public static final String API_METRICS_LOGGER = "API_METRICS_LOGGER"; + + public static final String SCHEDULED_TASK_LOGGER = "SCHEDULED_TASK_LOGGER"; +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/LoginConstant.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/LoginConstant.java new file mode 100644 index 00000000..bc95dbc2 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/LoginConstant.java @@ -0,0 +1,14 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +/** + * 登录常量 + * @author zengqiao + * @date 20/5/8 + */ +public class LoginConstant { + public static final String SESSION_USERNAME_KEY = "username"; + + public static final String COOKIE_CHINESE_USERNAME_KEY = "chineseName"; + + public static final Integer COOKIE_OR_SESSION_MAX_AGE_UNIT_MS = 24 * 60 * 60 * 1000; +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/SystemCodeConstant.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/SystemCodeConstant.java new file mode 100644 index 00000000..5fc76f03 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/SystemCodeConstant.java @@ -0,0 +1,17 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +/** + * @author zengqiao + * @date 20/7/28 + */ +public class SystemCodeConstant { + public static final String LOG_X = "LogX"; + + public static final String LEO = "leo"; + + public static final String DATA_DREAM = "datadream"; + + public static final String KAFKA_MANAGER = "kafka-manager"; + + public static final String CHORUS = "chorus"; // 治理平台-服务治理 +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/TopicCreationConstant.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/TopicCreationConstant.java new file mode 100644 index 00000000..423c6d1d --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/TopicCreationConstant.java @@ -0,0 +1,49 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +import java.util.Properties; + +/** + * @author zengqiao + * @date 20/7/28 + */ +public class TopicCreationConstant { + /** + * LogX创建Topic配置KEY + */ + public static final String LOG_X_CREATE_TOPIC_CONFIG_KEY_NAME = "LOG_X_CREATE_TOPIC_CONFIG"; + + /** + * 治理平台创建Topic配置KEY + */ + public static final String CHORUS_CREATE_TOPIC_CONFIG_KEY_NAME = "CHORUS_CREATE_TOPIC_CONFIG"; + + /** + * 内部创建Topic配置KEY + */ + public static final String INNER_CREATE_TOPIC_CONFIG_KEY = "INNER_CREATE_TOPIC_CONFIG_KEY"; + + public static final Integer DEFAULT_REPLICA = 3; + + public static final Integer DEFAULT_PARTITION_NUM = 1; + + public static final Integer DEFAULT_RETENTION_TIME_UNIT_HOUR = 24; + + public static final String TOPIC_RETENTION_TIME_KEY_NAME = "retention.ms"; + + public static Properties createNewProperties(Long retentionTime) { + Properties properties = new Properties(); + properties.put(TOPIC_RETENTION_TIME_KEY_NAME, String.valueOf(retentionTime)); + return properties; + } + + public static final Long AUTO_EXEC_MAX_BYTES_IN_UNIT_B = 30 * 1024 * 1024L; + + /** + * Topic 前缀 + */ + public static final String TOPIC_NAME_PREFIX_US = "us01_"; + + public static final String TOPIC_NAME_PREFIX_RU = "ru01_"; + + public static final Integer TOPIC_NAME_MAX_LENGTH = 255; +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/TopicSampleConstant.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/TopicSampleConstant.java new file mode 100644 index 00000000..5ee15331 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/constant/TopicSampleConstant.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.kafka.manager.common.constant; + +/** + * 采样相关配置 + * @author zengqiao + * @date 20/5/8 + */ +public class TopicSampleConstant { + /** + * TOPIC_SAMPLE_MAX_MSG_NUM: 最大采样条数 + * TOPIC_SAMPLE_MAX_TIMEOUT_MS:采样超时时间 + * TOPIC_SAMPLE_POLL_TIME_OUT_MS:采样单次poll超时时间 + * TOPIC_SAMPLE_MAX_DATA_LENGTH:截断情况下, 采样的数据最大长度 + */ + public static final Integer MAX_MSG_NUM = 100; + public static final Integer MAX_TIMEOUT_UNIT_MS = 10000; + public static final Integer POLL_TIME_OUT_UNIT_MS = 2000; + public static final Integer MAX_DATA_LENGTH_UNIT_BYTE = 2048; +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetadata.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetadata.java similarity index 73% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetadata.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetadata.java index ae943c7c..eb384c47 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetadata.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ConsumerMetadata.java @@ -3,6 +3,7 @@ package com.xiaojukeji.kafka.manager.common.entity; import kafka.admin.AdminClient; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * @author zengqiao @@ -15,12 +16,17 @@ public class ConsumerMetadata { private Map consumerGroupSummaryMap = new HashMap<>(); + private Map> consumerGroupAppMap = new ConcurrentHashMap<>(); + + public ConsumerMetadata(Set consumerGroupSet, Map> topicNameConsumerGroupMap, - Map consumerGroupSummaryMap) { + Map consumerGroupSummaryMap, + Map> consumerGroupAppMap) { this.consumerGroupSet = consumerGroupSet; this.topicNameConsumerGroupMap = topicNameConsumerGroupMap; this.consumerGroupSummaryMap = consumerGroupSummaryMap; + this.consumerGroupAppMap = consumerGroupAppMap; } public Set getConsumerGroupSet() { @@ -34,4 +40,8 @@ public class ConsumerMetadata { public Map getConsumerGroupSummaryMap() { return consumerGroupSummaryMap; } + + public Map> getConsumerGroupAppMap() { + return consumerGroupAppMap; + } } \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/DeprecatedResponseResult.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/DeprecatedResponseResult.java new file mode 100644 index 00000000..08b12721 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/DeprecatedResponseResult.java @@ -0,0 +1,83 @@ +package com.xiaojukeji.kafka.manager.common.entity; + +/** + * @author zengqiao + * @date 20/7/27 + */ +public class DeprecatedResponseResult { + public static final String SUCCESS_STATUS = "success"; + + public static final String FAILED_STATUS = "failure"; + + public static final String SUCCESS_MESSAGE = "process succeeded!"; + + public static final String FAILED_MESSAGE = "process failed!"; + + private String status; + + private String message; + + private T data; + + public static DeprecatedResponseResult success(T data) { + DeprecatedResponseResult responseCommonResult = new DeprecatedResponseResult(); + responseCommonResult.setMessage(SUCCESS_MESSAGE); + responseCommonResult.setStatus(SUCCESS_STATUS); + responseCommonResult.setData(data); + return responseCommonResult; + } + + public static DeprecatedResponseResult success() { + DeprecatedResponseResult responseCommonResult = new DeprecatedResponseResult(); + responseCommonResult.setStatus(SUCCESS_STATUS); + responseCommonResult.setMessage(SUCCESS_MESSAGE); + return responseCommonResult; + } + + public static DeprecatedResponseResult failure() { + DeprecatedResponseResult responseCommonResult = new DeprecatedResponseResult(); + responseCommonResult.setMessage(FAILED_MESSAGE); + responseCommonResult.setStatus(FAILED_STATUS); + return responseCommonResult; + } + + public static DeprecatedResponseResult failure(String message) { + DeprecatedResponseResult responseCommonResult = new DeprecatedResponseResult(); + responseCommonResult.setMessage(message); + responseCommonResult.setStatus(FAILED_STATUS); + return responseCommonResult; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + @Override + public String toString() { + return "DeprecatedResponseResult{" + + "status='" + status + '\'' + + ", message='" + message + '\'' + + ", data=" + data + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/KafkaVersion.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/KafkaVersion.java new file mode 100644 index 00000000..ba71d612 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/KafkaVersion.java @@ -0,0 +1,82 @@ +package com.xiaojukeji.kafka.manager.common.entity; + +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; + +/** + * @author zengqiao + * @date 20/6/15 + */ +public class KafkaVersion { + private static final String DIDI_VERSION_EXTEND = "d"; + + public static final Long VERSION_0_10_3 = 10030000L; // 0.10.2+ + public static final Long VERSION_MAX = Long.MAX_VALUE; + + private volatile String version = null; + + private volatile long versionNum = Long.MAX_VALUE; + + public boolean initialized() { + if (ValidateUtils.isNull(version)) { + return false; + } + return true; + } + + public String getVersion() { + return version; + } + + public long getVersionNum() { + return versionNum; + } + + @Override + public String toString() { + return "KafkaVersion{" + + "version='" + version + '\'' + + ", versionNum=" + versionNum + + '}'; + } + + public long init(String version) { + version = version.toLowerCase(); + String[] splitElems = version.split("-"); + int splitElemLength = splitElems.length; + if (splitElemLength <= 0) { + versionNum = Long.MAX_VALUE; + return versionNum; + } + + try { + // kafka的version + String[] kafkaVersion = splitElems[0].split("\\."); + int kafkaVersionLength = kafkaVersion.length; + + versionNum = kafkaVersionLength > 0? Integer.valueOf(kafkaVersion[0]): 0; + versionNum = versionNum * 100 + (kafkaVersionLength > 1? Integer.valueOf(kafkaVersion[1]): 0); + versionNum = versionNum * 100 + (kafkaVersionLength > 2? Integer.valueOf(kafkaVersion[2]): 0); + } catch (Exception e) { + // Kafka版本信息获取不到时, 直接返回空 + this.versionNum = Long.MAX_VALUE; + return versionNum; + } + + // 成功获取版本信息 + versionNum = versionNum * 10000; + this.version = version; + + // 补充扩展信息 + try { + for (int idx = 0; idx < splitElemLength; ++idx) { + if (splitElems[idx].equals(DIDI_VERSION_EXTEND) && idx < splitElemLength - 1) { + versionNum = versionNum + (Integer.valueOf(splitElems[idx + 1])); + return versionNum; + } + } + } catch (Exception e) { + // 扩展版本信息获取不到时, 忽略 + } + return versionNum; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/Result.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/Result.java similarity index 52% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/Result.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/Result.java index 27561377..7fc3343f 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/Result.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/Result.java @@ -1,7 +1,6 @@ package com.xiaojukeji.kafka.manager.common.entity; import com.alibaba.fastjson.JSON; -import com.xiaojukeji.kafka.manager.common.constant.StatusCode; import java.io.Serializable; @@ -14,12 +13,13 @@ public class Result implements Serializable { private T data; private String message; - private Integer code; + private String tips; + private int code; public Result(T data) { this.data = data; - this.code = StatusCode.SUCCESS; - this.message = "成功"; + this.code = ResultStatus.SUCCESS.getCode(); + this.message = ResultStatus.SUCCESS.getMessage(); } public Result() { @@ -37,7 +37,6 @@ public class Result implements Serializable { this.code = code; } - public T getData() { return (T)this.data; @@ -58,12 +57,20 @@ public class Result implements Serializable { this.message = message; } - public Integer getCode() + public String getTips() { + return tips; + } + + public void setTips(String tips) { + this.tips = tips; + } + + public int getCode() { return this.code; } - public void setCode(Integer code) + public void setCode(int code) { this.code = code; } @@ -73,4 +80,26 @@ public class Result implements Serializable { { return JSON.toJSONString(this); } + + public static Result buildSuc() { + Result result = new Result(); + result.setCode(ResultStatus.SUCCESS.getCode()); + result.setMessage(ResultStatus.SUCCESS.getMessage()); + return result; + } + + public static Result buildFrom(ResultStatus resultStatus) { + Result result = new Result(); + result.setCode(resultStatus.getCode()); + result.setMessage(resultStatus.getMessage()); + return result; + } + + public static Result buildFrom(ResultStatus resultStatus, Object data) { + Result result = new Result(); + result.setCode(resultStatus.getCode()); + result.setMessage(resultStatus.getMessage()); + result.setData(data); + return result; + } } diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ResultStatus.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ResultStatus.java new file mode 100644 index 00000000..b63151ac --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ResultStatus.java @@ -0,0 +1,154 @@ +package com.xiaojukeji.kafka.manager.common.entity; + +import com.xiaojukeji.kafka.manager.common.constant.Constant; + +/** + * 返回状态 + * @author zengqiao + * @date 20/4/16 + */ +public enum ResultStatus { + SUCCESS(Constant.SUCCESS, "success"), + LOGIN_FAILED(1, "login failed, please check username and password"), + + + /** + * 内部依赖错误, [1000, 1200) + * ------------------------------------------------------------------------------------------ + */ + MYSQL_ERROR(1000, "operate database failed"), + + CONNECT_ZOOKEEPER_FAILED(1000, "connect zookeeper failed"), + READ_ZOOKEEPER_FAILED(1000, "read zookeeper failed"), + READ_JMX_FAILED(1000, "read jmx failed"), + + + // 内部依赖错误 —— Kafka特定错误, [1000, 1100) + BROKER_NUM_NOT_ENOUGH(1000, "broker not enough"), + CONTROLLER_NOT_ALIVE(1000, "controller not alive"), + CLUSTER_METADATA_ERROR(1000, "cluster metadata error"), + TOPIC_CONFIG_ERROR(1000, "topic config error"), + + + /** + * 外部依赖错误, [1200, 1400) + * ------------------------------------------------------------------------------------------ + */ + CALL_CLUSTER_TASK_AGENT_FAILED(1000, " call cluster task agent failed"), + CALL_MONITOR_SYSTEM_ERROR(1000, " call monitor-system failed"), + + + + /** + * 外部用户操作错误, [1400, 1600) + * ------------------------------------------------------------------------------------------ + */ + PARAM_ILLEGAL(1400, "param illegal"), + OPERATION_FAILED(1401, "operation failed"), + OPERATION_FORBIDDEN(1402, "operation forbidden"), + API_CALL_EXCEED_LIMIT(1403, "api call exceed limit"), + + // 资源不存在 + CLUSTER_NOT_EXIST(10000, "cluster not exist"), + BROKER_NOT_EXIST(10000, "broker not exist"), + TOPIC_NOT_EXIST(10000, "topic not exist"), + PARTITION_NOT_EXIST(10000, "partition not exist"), + + ACCOUNT_NOT_EXIST(10000, "account not exist"), + APP_NOT_EXIST(1000, "app not exist"), + ORDER_NOT_EXIST(1000, "order not exist"), + CONFIG_NOT_EXIST(1000, "config not exist"), + IDC_NOT_EXIST(1000, "idc not exist"), + TASK_NOT_EXIST(1110, "task not exist"), + + AUTHORITY_NOT_EXIST(1000, "authority not exist"), + + MONITOR_NOT_EXIST(1110, "monitor not exist"), + + QUOTA_NOT_EXIST(1000, "quota not exist, please check clusterId, topicName and appId"), + + // 资源不存在, 已存在, 已被使用 + RESOURCE_NOT_EXIST(1200, "资源不存在"), + RESOURCE_ALREADY_EXISTED(1200, "资源已经存在"), + RESOURCE_NAME_DUPLICATED(1200, "资源名称重复"), + RESOURCE_ALREADY_USED(1000, "资源早已被使用"), + + + /** + * 资源参数错误 + */ + CG_LOCATION_ILLEGAL(10000, "consumer group location illegal"), + ORDER_ALREADY_HANDLED(1000, "order already handled"), + + APP_ID_OR_PASSWORD_ILLEGAL(1000, "app or password illegal"), + SYSTEM_CODE_ILLEGAL(1000, "system code illegal"), + + + + + + + + + + /////////////////////////////////////////////////////////////// + + USER_WITHOUT_AUTHORITY(1000, "user without authority"), + + + + JSON_PARSER_ERROR(1000, "json parser error"), + + + TOPIC_OPERATION_PARAM_NULL_POINTER(2, "参数错误"), + TOPIC_OPERATION_PARTITION_NUM_ILLEGAL(3, "分区数错误"), + TOPIC_OPERATION_BROKER_NUM_NOT_ENOUGH(4, "Broker数不足错误"), + TOPIC_OPERATION_TOPIC_NAME_ILLEGAL(5, "Topic名称非法"), + TOPIC_OPERATION_TOPIC_EXISTED(6, "Topic已存在"), + TOPIC_OPERATION_UNKNOWN_TOPIC_PARTITION(7, "Topic未知"), + TOPIC_OPERATION_TOPIC_CONFIG_ILLEGAL(8, "Topic配置错误"), + TOPIC_OPERATION_TOPIC_IN_DELETING(9, "Topic正在删除"), + TOPIC_OPERATION_UNKNOWN_ERROR(10, "未知错误"), + TOPIC_EXIST_CONNECT_CANNOT_DELETE(10, "topic exist connect cannot delete"), + EXIST_TOPIC_CANNOT_DELETE(10, "exist topic cannot delete"), + + + /** + * 工单 + */ + CHANGE_ZOOKEEPER_FORBIDEN(100, "change zookeeper forbiden"), +// APP_EXIST_TOPIC_AUTHORITY_CANNOT_DELETE(1000, "app exist topic authority cannot delete"), + + UPLOAD_FILE_FAIL(1000, "upload file fail"), + FILE_TYPE_NOT_SUPPORT(1000, "File type not support"), + DOWNLOAD_FILE_FAIL(1000, "download file fail"), + + + TOPIC_ALREADY_EXIST(17400, "topic already existed"), + CONSUMER_GROUP_NOT_EXIST(17411, "consumerGroup not exist"), + ; + + private int code; + private String message; + + ResultStatus(int code, String message) { + this.code = code; + this.message = message; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/TopicOperationResult.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/TopicOperationResult.java new file mode 100644 index 00000000..3c979d8d --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/TopicOperationResult.java @@ -0,0 +1,83 @@ +package com.xiaojukeji.kafka.manager.common.entity; + +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/2 + */ +public class TopicOperationResult { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "状态码, 0:成功, 其他失败") + private Integer code; + + @ApiModelProperty(value = "信息") + private String message; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return "TopicOperationResult{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", code=" + code + + ", message='" + message + '\'' + + '}'; + } + + public static TopicOperationResult buildFrom(Long clusterId, String topicName, Result rs) { + return buildFrom(clusterId, topicName, rs.getCode(), rs.getMessage()); + } + + public static TopicOperationResult buildFrom(Long clusterId, String topicName, ResultStatus rs) { + return buildFrom(clusterId, topicName, rs.getCode(), rs.getMessage()); + } + + private static TopicOperationResult buildFrom(Long clusterId, + String topicName, + Integer code, + String message) { + TopicOperationResult result = new TopicOperationResult(); + result.setClusterId(clusterId); + result.setTopicName(topicName); + result.setCode(code); + result.setMessage(message); + return result; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/AppTopicDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/AppTopicDTO.java new file mode 100644 index 00000000..ac202605 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/AppTopicDTO.java @@ -0,0 +1,91 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao; + +/** + * AppTopic信息 + * @author zengqiao + * @date 20/5/11 + */ +public class AppTopicDTO { + private Long logicalClusterId; + + private String logicalClusterName; + + private Long physicalClusterId; + + private String topicName; + + private Integer access; + + private String operator; + + private Long gmtCreate; + + public Long getLogicalClusterId() { + return logicalClusterId; + } + + public void setLogicalClusterId(Long logicalClusterId) { + this.logicalClusterId = logicalClusterId; + } + + public String getLogicalClusterName() { + return logicalClusterName; + } + + public void setLogicalClusterName(String logicalClusterName) { + this.logicalClusterName = logicalClusterName; + } + + public Long getPhysicalClusterId() { + return physicalClusterId; + } + + public void setPhysicalClusterId(Long physicalClusterId) { + this.physicalClusterId = physicalClusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getAccess() { + return access; + } + + public void setAccess(Integer access) { + this.access = access; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } + + @Override + public String toString() { + return "AppTopicDTO{" + + "logicalClusterId=" + logicalClusterId + + ", logicalClusterName='" + logicalClusterName + '\'' + + ", physicalClusterId=" + physicalClusterId + + ", topicName='" + topicName + '\'' + + ", access=" + access + + ", operator='" + operator + '\'' + + ", gmtCreate=" + gmtCreate + + '}'; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerBasicDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/BrokerBasicDTO.java similarity index 97% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerBasicDTO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/BrokerBasicDTO.java index 384cdf33..eb8e01d2 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/BrokerBasicDTO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/BrokerBasicDTO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto; +package com.xiaojukeji.kafka.manager.common.entity.ao; /** * Broker基本信息 diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/BrokerOverviewDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/BrokerOverviewDTO.java new file mode 100644 index 00000000..7ce643b6 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/BrokerOverviewDTO.java @@ -0,0 +1,189 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao; + +import com.xiaojukeji.kafka.manager.common.entity.metrics.BrokerMetrics; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import com.xiaojukeji.kafka.manager.common.zookeeper.znode.brokers.BrokerMetadata; + +/** + * @author zengqiao_cn@163.com + * @date 19/4/21 + */ +public class BrokerOverviewDTO { + private Integer brokerId; + + private String host; + + private Integer port; + + private Integer jmxPort; + + private Long startTime; + + private Object byteIn; + + private Object byteOut; + + private Integer partitionCount; + + private Integer underReplicatedPartitions; + + private Boolean underReplicated; + + private Integer status; + + private Integer peakFlowStatus; + + private String kafkaVersion; + + private Integer leaderCount; + + public Integer getBrokerId() { + return brokerId; + } + + public void setBrokerId(Integer brokerId) { + this.brokerId = brokerId; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public Integer getJmxPort() { + return jmxPort; + } + + public void setJmxPort(Integer jmxPort) { + this.jmxPort = jmxPort; + } + + public Long getStartTime() { + return startTime; + } + + public void setStartTime(Long startTime) { + this.startTime = startTime; + } + + public Object getByteIn() { + return byteIn; + } + + public void setByteIn(Object byteIn) { + this.byteIn = byteIn; + } + + public Object getByteOut() { + return byteOut; + } + + public void setByteOut(Object byteOut) { + this.byteOut = byteOut; + } + + public Integer getPartitionCount() { + return partitionCount; + } + + public void setPartitionCount(Integer partitionCount) { + this.partitionCount = partitionCount; + } + + public Integer getUnderReplicatedPartitions() { + return underReplicatedPartitions; + } + + public void setUnderReplicatedPartitions(Integer underReplicatedPartitions) { + this.underReplicatedPartitions = underReplicatedPartitions; + } + + public Boolean getUnderReplicated() { + return underReplicated; + } + + public void setUnderReplicated(Boolean underReplicated) { + this.underReplicated = underReplicated; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getPeakFlowStatus() { + return peakFlowStatus; + } + + public void setPeakFlowStatus(Integer peakFlowStatus) { + this.peakFlowStatus = peakFlowStatus; + } + + public String getKafkaVersion() { + return kafkaVersion; + } + + public void setKafkaVersion(String kafkaVersion) { + this.kafkaVersion = kafkaVersion; + } + + public Integer getLeaderCount() { + return leaderCount; + } + + public void setLeaderCount(Integer leaderCount) { + this.leaderCount = leaderCount; + } + + public static BrokerOverviewDTO newInstance(BrokerMetadata brokerMetadata, + BrokerMetrics brokerMetrics, + String kafkaVersion) { + BrokerOverviewDTO brokerOverviewDTO = new BrokerOverviewDTO(); + brokerOverviewDTO.setBrokerId(brokerMetadata.getBrokerId()); + brokerOverviewDTO.setHost(brokerMetadata.getHost()); + brokerOverviewDTO.setPort(brokerMetadata.getPort()); + brokerOverviewDTO.setJmxPort(brokerMetadata.getJmxPort()); + brokerOverviewDTO.setStartTime(brokerMetadata.getTimestamp()); + brokerOverviewDTO.setStatus(0); + if (brokerMetrics == null) { + return brokerOverviewDTO; + } + brokerOverviewDTO.setByteIn( + brokerMetrics.getSpecifiedMetrics("BytesInPerSecOneMinuteRate") + ); + brokerOverviewDTO.setByteOut( + brokerMetrics.getSpecifiedMetrics("BytesOutPerSecOneMinuteRate") + ); + brokerOverviewDTO.setPartitionCount( + brokerMetrics.getSpecifiedMetrics("PartitionCountValue", Integer.class) + ); + brokerOverviewDTO.setUnderReplicatedPartitions( + brokerMetrics.getSpecifiedMetrics("UnderReplicatedPartitionsValue", Integer.class) + ); + + if (!ValidateUtils.isNull(brokerOverviewDTO.getUnderReplicatedPartitions())) { + brokerOverviewDTO.setUnderReplicated(brokerOverviewDTO.getUnderReplicatedPartitions() > 0); + } + brokerOverviewDTO.setLeaderCount( + brokerMetrics.getSpecifiedMetrics("LeaderCountValue", Integer.class) + ); + brokerOverviewDTO.setKafkaVersion(kafkaVersion); + return brokerOverviewDTO; + } + + +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/cluster/ClusterDetailVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/ClusterDetailDTO.java similarity index 56% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/cluster/ClusterDetailVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/ClusterDetailDTO.java index e5d2bf7c..937d9cf8 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/cluster/ClusterDetailVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/ClusterDetailDTO.java @@ -1,65 +1,43 @@ -package com.xiaojukeji.kafka.manager.web.vo.cluster; +package com.xiaojukeji.kafka.manager.common.entity.ao; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import java.util.Date; /** - * ClusterDetailVO - * @author huangyiminghappy@163.com - * @date 2019/3/15 + * @author zengqiao + * @date 20/4/23 */ -@ApiModel(value="ClusterDetailVO", description="集群详细信息") -public class ClusterDetailVO { - @ApiModelProperty(value="集群Id") +public class ClusterDetailDTO { private Long clusterId; - @ApiModelProperty(value="集群名称") private String clusterName; - @ApiModelProperty(value="集群ZK地址") private String zookeeper; - @ApiModelProperty(value="bootstrap地址") private String bootstrapServers; - @ApiModelProperty(value="kafka版本") private String kafkaVersion; - @ApiModelProperty(value="broker数量") - private Integer brokerNum; + private String idc; - @ApiModelProperty(value="topic数量") - private Integer topicNum; + private Integer mode; - @ApiModelProperty(value="consumerGroup数量") - private Integer consumerGroupNum; + private String securityProperties; - @ApiModelProperty(value="controllerId") - private Integer controllerId; - - @ApiModelProperty(value="安全协议") - private String securityProtocol; - - @ApiModelProperty(value="SASL机制") - private String saslMechanism; - - @ApiModelProperty(value="SASL的JSSA配置") - private String saslJaasConfig; - - @ApiModelProperty(value="regionNum数") - private Integer regionNum; - - @ApiModelProperty(value = "开启告警[0:不开启, 1:开启]") - private Integer alarmFlag; - - @ApiModelProperty(value="是否已经删除,0不删除,1删除") private Integer status; - @ApiModelProperty(value="集群创建时间") - private Long gmtCreate; + private Date gmtCreate; - @ApiModelProperty(value="集群修改时间") - private Long gmtModify; + private Date gmtModify; + + private Integer brokerNum; + + private Integer topicNum; + + private Integer consumerGroupNum; + + private Integer controllerId; + + private Integer regionNum; public Long getClusterId() { return clusterId; @@ -101,6 +79,54 @@ public class ClusterDetailVO { this.kafkaVersion = kafkaVersion; } + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public Integer getMode() { + return mode; + } + + public void setMode(Integer mode) { + this.mode = mode; + } + + public String getSecurityProperties() { + return securityProperties; + } + + public void setSecurityProperties(String securityProperties) { + this.securityProperties = securityProperties; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + public Integer getBrokerNum() { return brokerNum; } @@ -133,30 +159,6 @@ public class ClusterDetailVO { this.controllerId = controllerId; } - public String getSecurityProtocol() { - return securityProtocol; - } - - public void setSecurityProtocol(String securityProtocol) { - this.securityProtocol = securityProtocol; - } - - public String getSaslMechanism() { - return saslMechanism; - } - - public void setSaslMechanism(String saslMechanism) { - this.saslMechanism = saslMechanism; - } - - public String getSaslJaasConfig() { - return saslJaasConfig; - } - - public void setSaslJaasConfig(String saslJaasConfig) { - this.saslJaasConfig = saslJaasConfig; - } - public Integer getRegionNum() { return regionNum; } @@ -165,58 +167,25 @@ public class ClusterDetailVO { this.regionNum = regionNum; } - public Integer getAlarmFlag() { - return alarmFlag; - } - - public void setAlarmFlag(Integer alarmFlag) { - this.alarmFlag = alarmFlag; - } - - public Integer getStatus() { - return status; - } - - public void setStatus(Integer status) { - this.status = status; - } - - public Long getGmtCreate() { - return gmtCreate; - } - - public void setGmtCreate(Long gmtCreate) { - this.gmtCreate = gmtCreate; - } - - public Long getGmtModify() { - return gmtModify; - } - - public void setGmtModify(Long gmtModify) { - this.gmtModify = gmtModify; - } - @Override public String toString() { - return "ClusterDetailVO{" + + return "ClusterDetailDTO{" + "clusterId=" + clusterId + ", clusterName='" + clusterName + '\'' + ", zookeeper='" + zookeeper + '\'' + ", bootstrapServers='" + bootstrapServers + '\'' + ", kafkaVersion='" + kafkaVersion + '\'' + + ", idc='" + idc + '\'' + + ", mode='" + mode + '\'' + + ", securityProperties='" + securityProperties + '\'' + + ", status=" + status + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + ", brokerNum=" + brokerNum + ", topicNum=" + topicNum + ", consumerGroupNum=" + consumerGroupNum + ", controllerId=" + controllerId + - ", securityProtocol='" + securityProtocol + '\'' + - ", saslMechanism='" + saslMechanism + '\'' + - ", saslJaasConfig='" + saslJaasConfig + '\'' + ", regionNum=" + regionNum + - ", alarmFlag=" + alarmFlag + - ", status=" + status + - ", gmtCreate=" + gmtCreate + - ", gmtModify=" + gmtModify + '}'; } -} +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/PartitionAttributeDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/PartitionAttributeDTO.java new file mode 100644 index 00000000..e9e648ff --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/PartitionAttributeDTO.java @@ -0,0 +1,24 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao; + +/** + * @author zhongyuankai + * @date 2020/5/26 + */ +public class PartitionAttributeDTO { + private Long logSize; + + public Long getLogSize() { + return logSize; + } + + public void setLogSize(Long logSize) { + this.logSize = logSize; + } + + @Override + public String toString() { + return "PartitionAttributeDTO{" + + "logSize=" + logSize + + '}'; + } +} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/PartitionOffsetDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/PartitionOffsetDTO.java similarity index 95% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/PartitionOffsetDTO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/PartitionOffsetDTO.java index 3ce2059f..bfe80a6b 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/PartitionOffsetDTO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/PartitionOffsetDTO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto; +package com.xiaojukeji.kafka.manager.common.entity.ao; /** * Topic Offset diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/RdTopicBasic.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/RdTopicBasic.java new file mode 100644 index 00000000..3cecd3cf --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/RdTopicBasic.java @@ -0,0 +1,103 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao; + +import java.util.Properties; + +/** + * @author zengqiao + * @date 20/6/10 + */ +public class RdTopicBasic { + private Long clusterId; + + private String clusterName; + + private String topicName; + + private Long retentionTime; + + private String appId; + + private String appName; + + private Properties properties; + + private String description; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Long getRetentionTime() { + return retentionTime; + } + + public void setRetentionTime(Long retentionTime) { + this.retentionTime = retentionTime; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties properties) { + this.properties = properties; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "RdTopicBasic{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", retentionTime=" + retentionTime + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", properties=" + properties + + ", description='" + description + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/TopicDiskLocation.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/TopicDiskLocation.java new file mode 100644 index 00000000..dde7deb8 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/TopicDiskLocation.java @@ -0,0 +1,103 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/7/8 + */ +public class TopicDiskLocation { + private Long clusterId; + + private String topicName; + + private Integer brokerId; + + private String diskName; + + private List leaderPartitions; + + private List followerPartitions; + + private Boolean isUnderReplicated; + + private List underReplicatedPartitions; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getBrokerId() { + return brokerId; + } + + public void setBrokerId(Integer brokerId) { + this.brokerId = brokerId; + } + + public String getDiskName() { + return diskName; + } + + public void setDiskName(String diskName) { + this.diskName = diskName; + } + + public List getLeaderPartitions() { + return leaderPartitions; + } + + public void setLeaderPartitions(List leaderPartitions) { + this.leaderPartitions = leaderPartitions; + } + + public List getFollowerPartitions() { + return followerPartitions; + } + + public void setFollowerPartitions(List followerPartitions) { + this.followerPartitions = followerPartitions; + } + + public Boolean getUnderReplicated() { + return isUnderReplicated; + } + + public void setUnderReplicated(Boolean underReplicated) { + isUnderReplicated = underReplicated; + } + + public List getUnderReplicatedPartitions() { + return underReplicatedPartitions; + } + + public void setUnderReplicatedPartitions(List underReplicatedPartitions) { + this.underReplicatedPartitions = underReplicatedPartitions; + } + + @Override + public String toString() { + return "TopicDiskLocation{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", brokerId=" + brokerId + + ", diskName='" + diskName + '\'' + + ", leaderPartitions=" + leaderPartitions + + ", followerPartitions=" + followerPartitions + + ", isUnderReplicated=" + isUnderReplicated + + ", underReplicatedPartitions=" + underReplicatedPartitions + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/account/Account.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/account/Account.java new file mode 100644 index 00000000..b387e6d5 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/account/Account.java @@ -0,0 +1,71 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.account; + +import com.xiaojukeji.kafka.manager.common.bizenum.AccountRoleEnum; + +/** + * 用户信息 + * @author zengqiao + * @date 20/6/10 + */ +public class Account { + private String username; + + private String chineseName; + + private String department; + + private AccountRoleEnum accountRoleEnum; + + public Account(String username, String chineseName, String department, AccountRoleEnum accountRoleEnum) { + this.username = username; + this.chineseName = chineseName; + this.department = department; + this.accountRoleEnum = accountRoleEnum; + } + + public Account() { + super(); + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getChineseName() { + return chineseName; + } + + public void setChineseName(String chineseName) { + this.chineseName = chineseName; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public AccountRoleEnum getAccountRoleEnum() { + return accountRoleEnum; + } + + public void setAccountRoleEnum(AccountRoleEnum accountRoleEnum) { + this.accountRoleEnum = accountRoleEnum; + } + + @Override + public String toString() { + return "Account{" + + "username='" + username + '\'' + + ", chineseName='" + chineseName + '\'' + + ", department='" + department + '\'' + + ", accountRoleEnum=" + accountRoleEnum + + '}'; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/analysis/AnalysisBrokerDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/analysis/AnalysisBrokerDTO.java similarity index 97% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/analysis/AnalysisBrokerDTO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/analysis/AnalysisBrokerDTO.java index b47e071b..a5441f86 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/analysis/AnalysisBrokerDTO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/analysis/AnalysisBrokerDTO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto.analysis; +package com.xiaojukeji.kafka.manager.common.entity.ao.analysis; import java.util.List; diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/analysis/AnalysisTopicDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/analysis/AnalysisTopicDTO.java similarity index 98% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/analysis/AnalysisTopicDTO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/analysis/AnalysisTopicDTO.java index 6428f3a4..cf78e887 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/analysis/AnalysisTopicDTO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/analysis/AnalysisTopicDTO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto.analysis; +package com.xiaojukeji.kafka.manager.common.entity.ao.analysis; /** * @author zengqiao diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/api/ApiCount.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/api/ApiCount.java new file mode 100644 index 00000000..aefe940a --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/api/ApiCount.java @@ -0,0 +1,50 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.api; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author zengqiao + * @date 20/7/27 + */ +public class ApiCount { + private int apiLevel; + + private Integer maxNum; + + private AtomicInteger currentNum; + + public ApiCount(int apiLevel, Integer maxNum, AtomicInteger currentNum) { + this.apiLevel = apiLevel; + this.maxNum = maxNum; + this.currentNum = currentNum; + } + + public int getApiLevel() { + return apiLevel; + } + + public Integer getMaxNum() { + return maxNum; + } + + public AtomicInteger getCurrentNum() { + return currentNum; + } + + public Boolean incAndCheckIsOverFlow() { + return maxNum < currentNum.incrementAndGet(); + } + + public int decPresentNum() { + return currentNum.decrementAndGet(); + } + + @Override + public String toString() { + return "ApiCount{" + + "apiLevel=" + apiLevel + + ", maxNum=" + maxNum + + ", currentNum=" + currentNum + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/ClusterBrokerStatus.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/ClusterBrokerStatus.java new file mode 100644 index 00000000..33f1e74e --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/ClusterBrokerStatus.java @@ -0,0 +1,37 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.cluster; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/7/14 + */ +public class ClusterBrokerStatus { + private List brokerReplicaStatusList; + + private List brokerBytesInStatusList; + + public List getBrokerReplicaStatusList() { + return brokerReplicaStatusList; + } + + public void setBrokerReplicaStatusList(List brokerReplicaStatusList) { + this.brokerReplicaStatusList = brokerReplicaStatusList; + } + + public List getBrokerBytesInStatusList() { + return brokerBytesInStatusList; + } + + public void setBrokerBytesInStatusList(List brokerBytesInStatusList) { + this.brokerBytesInStatusList = brokerBytesInStatusList; + } + + @Override + public String toString() { + return "ClusterBrokerStatus{" + + "brokerReplicaStatusList=" + brokerReplicaStatusList + + ", brokerBytesInStatusList=" + brokerBytesInStatusList + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/LogicalCluster.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/LogicalCluster.java new file mode 100644 index 00000000..86941d0e --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/LogicalCluster.java @@ -0,0 +1,123 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.cluster; + +/** + * @author zengqiao + * @date 20/4/1 + */ +public class LogicalCluster { + private Long logicalClusterId; + + private String logicalClusterName; + + private Integer mode; + + private Integer topicNum; + + private String clusterVersion; + + private Long physicalClusterId; + + private String bootstrapServers; + + private String description; + + private Long gmtCreate; + + private Long gmtModify; + + public Long getLogicalClusterId() { + return logicalClusterId; + } + + public void setLogicalClusterId(Long logicalClusterId) { + this.logicalClusterId = logicalClusterId; + } + + public String getLogicalClusterName() { + return logicalClusterName; + } + + public void setLogicalClusterName(String logicalClusterName) { + this.logicalClusterName = logicalClusterName; + } + + public Integer getMode() { + return mode; + } + + public void setMode(Integer mode) { + this.mode = mode; + } + + public Integer getTopicNum() { + return topicNum; + } + + public void setTopicNum(Integer topicNum) { + this.topicNum = topicNum; + } + + public String getClusterVersion() { + return clusterVersion; + } + + public void setClusterVersion(String clusterVersion) { + this.clusterVersion = clusterVersion; + } + + public Long getPhysicalClusterId() { + return physicalClusterId; + } + + public void setPhysicalClusterId(Long physicalClusterId) { + this.physicalClusterId = physicalClusterId; + } + + public String getBootstrapServers() { + return bootstrapServers; + } + + public void setBootstrapServers(String bootstrapServers) { + this.bootstrapServers = bootstrapServers; + } + + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Long getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Long gmtModify) { + this.gmtModify = gmtModify; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "LogicalCluster{" + + "logicalClusterId=" + logicalClusterId + + ", logicalClusterName='" + logicalClusterName + '\'' + + ", mode=" + mode + + ", topicNum=" + topicNum + + ", clusterVersion='" + clusterVersion + '\'' + + ", physicalClusterId=" + physicalClusterId + + ", bootstrapServers='" + bootstrapServers + '\'' + + ", description='" + description + '\'' + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + '}'; + } +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicMetricsVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/LogicalClusterMetrics.java similarity index 70% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicMetricsVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/LogicalClusterMetrics.java index 7ca5000c..a3cb9c34 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicMetricsVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/cluster/LogicalClusterMetrics.java @@ -1,40 +1,23 @@ -package com.xiaojukeji.kafka.manager.web.vo.topic; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +package com.xiaojukeji.kafka.manager.common.entity.ao.cluster; /** - * @author huangyiminghappy@163.com - * @date 2019-03-20 + * @author zengqiao + * @date 20/6/29 */ -@ApiModel(value = "Topic流量信息") -public class TopicMetricsVO { - @ApiModelProperty(value = "每秒流入消息数") - private Double messagesInPerSec = 0.0; +public class LogicalClusterMetrics { - @ApiModelProperty(value = "每秒流入字节数") - private Double bytesInPerSec = 0.0; - - @ApiModelProperty(value = "每秒流出字节数") - private Double bytesOutPerSec = 0.0; - - @ApiModelProperty(value = "每秒拒绝字节数") - private Double bytesRejectedPerSec = 0.0; - - @ApiModelProperty(value = "每秒请求数") private Double totalProduceRequestsPerSec = 0.0; - @ApiModelProperty(value = "创建时间") + private Double bytesInPerSec = 0.0; + + private Double bytesOutPerSec = 0.0; + + private Double bytesRejectedPerSec = 0.0; + + private Double messagesInPerSec = 0.0; + private Long gmtCreate; - public Double getMessagesInPerSec() { - return messagesInPerSec; - } - - public void setMessagesInPerSec(Double messagesInPerSec) { - this.messagesInPerSec = messagesInPerSec; - } - public Double getBytesInPerSec() { return bytesInPerSec; } @@ -59,12 +42,12 @@ public class TopicMetricsVO { this.bytesRejectedPerSec = bytesRejectedPerSec; } - public Double getTotalProduceRequestsPerSec() { - return totalProduceRequestsPerSec; + public Double getMessagesInPerSec() { + return messagesInPerSec; } - public void setTotalProduceRequestsPerSec(Double totalProduceRequestsPerSec) { - this.totalProduceRequestsPerSec = totalProduceRequestsPerSec; + public void setMessagesInPerSec(Double messagesInPerSec) { + this.messagesInPerSec = messagesInPerSec; } public Long getGmtCreate() { @@ -75,15 +58,23 @@ public class TopicMetricsVO { this.gmtCreate = gmtCreate; } + public Double getTotalProduceRequestsPerSec() { + return totalProduceRequestsPerSec; + } + + public void setTotalProduceRequestsPerSec(Double totalProduceRequestsPerSec) { + this.totalProduceRequestsPerSec = totalProduceRequestsPerSec; + } + @Override public String toString() { - return "TopicMetricsVO{" + - "messagesInPerSec=" + messagesInPerSec + + return "LogicalClusterMetrics{" + + "totalProduceRequestsPerSec=" + totalProduceRequestsPerSec + ", bytesInPerSec=" + bytesInPerSec + ", bytesOutPerSec=" + bytesOutPerSec + ", bytesRejectedPerSec=" + bytesRejectedPerSec + - ", totalProduceRequestsPerSec=" + totalProduceRequestsPerSec + + ", messagesInPerSec=" + messagesInPerSec + ", gmtCreate=" + gmtCreate + '}'; } -} +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/CreateTopicConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/CreateTopicConfig.java new file mode 100644 index 00000000..35f694f8 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/CreateTopicConfig.java @@ -0,0 +1,26 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.config; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/7/24 + */ +public class CreateTopicConfig { + private List configList; + + public List getConfigList() { + return configList; + } + + public void setConfigList(List configList) { + this.configList = configList; + } + + @Override + public String toString() { + return "CreateTopicConfig{" + + "configList=" + configList + + '}'; + } +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/AdminExpandTopicModel.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/CreateTopicElemConfig.java similarity index 50% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/AdminExpandTopicModel.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/CreateTopicElemConfig.java index 057b7951..0f74b1e4 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/AdminExpandTopicModel.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/CreateTopicElemConfig.java @@ -1,32 +1,26 @@ -package com.xiaojukeji.kafka.manager.web.model.topic; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import org.springframework.util.StringUtils; +package com.xiaojukeji.kafka.manager.common.entity.ao.config; import java.util.List; /** * @author zengqiao - * @date 20/1/2 + * @date 20/7/24 */ -@ApiModel(value = "AdminExpandTopicModel") -public class AdminExpandTopicModel { - @ApiModelProperty(value = "集群ID") +public class CreateTopicElemConfig { private Long clusterId; - @ApiModelProperty(value = "topicName名称") - private String topicName; - - @ApiModelProperty(value = "分区数") - private Integer partitionNum; - - @ApiModelProperty(value = "brokerId列表") private List brokerIdList; - @ApiModelProperty(value = "regionId列表") private List regionIdList; + private Integer partitionNum; + + private Integer replicaNum; + + private Integer retentionTimeUnitHour; + + private Long autoExecMaxPeakBytesInUnitB; + public Long getClusterId() { return clusterId; } @@ -35,22 +29,6 @@ public class AdminExpandTopicModel { this.clusterId = clusterId; } - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - public Integer getPartitionNum() { - return partitionNum; - } - - public void setPartitionNum(Integer partitionNum) { - this.partitionNum = partitionNum; - } - public List getBrokerIdList() { return brokerIdList; } @@ -67,26 +45,48 @@ public class AdminExpandTopicModel { this.regionIdList = regionIdList; } - @Override - public String toString() { - return "AdminExpandTopicModel{" + - "clusterId=" + clusterId + - ", topicName='" + topicName + '\'' + - ", partitionNum=" + partitionNum + - ", brokerIdList=" + brokerIdList + - ", regionIdList=" + regionIdList + - '}'; + public Integer getReplicaNum() { + return replicaNum; } - public Boolean legal() { - if (clusterId == null - || StringUtils.isEmpty(topicName) - || partitionNum == null || partitionNum <= 0) { - return false; - } - if ((brokerIdList == null || brokerIdList.isEmpty()) && (regionIdList == null || regionIdList.isEmpty())) { - return false; - } - return true; + public void setReplicaNum(Integer replicaNum) { + this.replicaNum = replicaNum; + } + + public Integer getRetentionTimeUnitHour() { + return retentionTimeUnitHour; + } + + public void setRetentionTimeUnitHour(Integer retentionTimeUnitHour) { + this.retentionTimeUnitHour = retentionTimeUnitHour; + } + + public Long getAutoExecMaxPeakBytesInUnitB() { + return autoExecMaxPeakBytesInUnitB; + } + + public void setAutoExecMaxPeakBytesInUnitB(Long autoExecMaxPeakBytesInUnitB) { + this.autoExecMaxPeakBytesInUnitB = autoExecMaxPeakBytesInUnitB; + } + + public Integer getPartitionNum() { + return partitionNum; + } + + public void setPartitionNum(Integer partitionNum) { + this.partitionNum = partitionNum; + } + + @Override + public String toString() { + return "CreateTopicElemConfig{" + + "clusterId=" + clusterId + + ", brokerIdList=" + brokerIdList + + ", regionIdList=" + regionIdList + + ", partitionNum=" + partitionNum + + ", replicaNum=" + replicaNum + + ", retentionTimeUnitHour=" + retentionTimeUnitHour + + ", autoExecMaxPeakBytesInUnitB=" + autoExecMaxPeakBytesInUnitB + + '}'; } } \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/MaxAvgBytesInConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/MaxAvgBytesInConfig.java new file mode 100644 index 00000000..6a26f955 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/MaxAvgBytesInConfig.java @@ -0,0 +1,25 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.config; + +/** + * 峰值均值流入流量配置 + * @author zengqiao + * @date 20/6/9 + */ +public class MaxAvgBytesInConfig { + private Integer duration; + + public Integer getDuration() { + return duration; + } + + public void setDuration(Integer duration) { + this.duration = duration; + } + + @Override + public String toString() { + return "MaxAvgBytesInConfig{" + + "duration=" + duration + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/SinkTopicRequestTimeMetricsConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/SinkTopicRequestTimeMetricsConfig.java new file mode 100644 index 00000000..91faaba1 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/SinkTopicRequestTimeMetricsConfig.java @@ -0,0 +1,57 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.config; + +/** + * @author zengqiao + * @date 20/9/7 + */ +public class SinkTopicRequestTimeMetricsConfig { + private Long clusterId; + + private String topicName; + + private Long startId; + + private Long step; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Long getStartId() { + return startId; + } + + public void setStartId(Long startId) { + this.startId = startId; + } + + public Long getStep() { + return step; + } + + public void setStep(Long step) { + this.step = step; + } + + @Override + public String toString() { + return "SinkTopicRequestTimeMetricsConfig{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", startId=" + startId + + ", step=" + step + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/TopicAnomalyFlowConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/TopicAnomalyFlowConfig.java new file mode 100644 index 00000000..1797eb6e --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/TopicAnomalyFlowConfig.java @@ -0,0 +1,57 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.config; + +/** + * @author zengqiao + * @date 20/8/23 + */ +public class TopicAnomalyFlowConfig { + private Long minTopicBytesInUnitB; + + private Double bytesInIncUnitB; + + private Long minTopicProduceQps; + + private Double produceQpsInc; + + public Long getMinTopicBytesInUnitB() { + return minTopicBytesInUnitB; + } + + public void setMinTopicBytesInUnitB(Long minTopicBytesInUnitB) { + this.minTopicBytesInUnitB = minTopicBytesInUnitB; + } + + public Double getBytesInIncUnitB() { + return bytesInIncUnitB; + } + + public void setBytesInIncUnitB(Double bytesInIncUnitB) { + this.bytesInIncUnitB = bytesInIncUnitB; + } + + public Long getMinTopicProduceQps() { + return minTopicProduceQps; + } + + public void setMinTopicProduceQps(Long minTopicProduceQps) { + this.minTopicProduceQps = minTopicProduceQps; + } + + public Double getProduceQpsInc() { + return produceQpsInc; + } + + public void setProduceQpsInc(Double produceQpsInc) { + this.produceQpsInc = produceQpsInc; + } + + @Override + public String toString() { + return "TopicAnomalyFlowConfig{" + + "minTopicBytesInUnitB=" + minTopicBytesInUnitB + + ", bytesInIncUnitB=" + bytesInIncUnitB + + ", minTopicProduceQps=" + minTopicProduceQps + + ", produceQpsInc=" + produceQpsInc + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/TopicNameConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/TopicNameConfig.java new file mode 100644 index 00000000..787bd238 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/TopicNameConfig.java @@ -0,0 +1,44 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.config; + +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; + +/** + * @author zengqiao + * @date 20/8/31 + */ +public class TopicNameConfig { + private Long clusterId; + + private String topicName; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + @Override + public String toString() { + return "TopicNameConfig{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + '}'; + } + + public boolean legal() { + if (ValidateUtils.isNull(clusterId) || ValidateUtils.isBlank(topicName)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/RegionTopicHotConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/RegionTopicHotConfig.java new file mode 100644 index 00000000..030a3621 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/RegionTopicHotConfig.java @@ -0,0 +1,58 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.config.expert; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author zengqiao + * @date 20/8/23 + */ +public class RegionTopicHotConfig { + private Long minTopicBytesInUnitB; + + private Integer maxDisPartitionNum; + + private List ignoreClusterIdList; + + public Long getMinTopicBytesInUnitB() { + if (minTopicBytesInUnitB == null) { + return 3 * 1024 * 1024L; + } + return minTopicBytesInUnitB; + } + + public void setMinTopicBytesInUnitB(Long minTopicBytesInUnitB) { + this.minTopicBytesInUnitB = minTopicBytesInUnitB; + } + + public Integer getMaxDisPartitionNum() { + if (maxDisPartitionNum == null) { + return 3; + } + return maxDisPartitionNum; + } + + public void setMaxDisPartitionNum(Integer maxDisPartitionNum) { + this.maxDisPartitionNum = maxDisPartitionNum; + } + + public List getIgnoreClusterIdList() { + if (ignoreClusterIdList == null) { + return new ArrayList<>(); + } + return ignoreClusterIdList; + } + + public void setIgnoreClusterIdList(List ignoreClusterIdList) { + this.ignoreClusterIdList = ignoreClusterIdList; + } + + @Override + public String toString() { + return "RegionTopicHotConfig{" + + "minTopicBytesInUnitB=" + minTopicBytesInUnitB + + ", maxDisPartitionNum=" + maxDisPartitionNum + + ", ignoreClusterIdList=" + ignoreClusterIdList + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/TopicExpiredConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/TopicExpiredConfig.java new file mode 100644 index 00000000..d68dc2ba --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/TopicExpiredConfig.java @@ -0,0 +1,38 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.config.expert; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author zengqiao + * @date 20/9/17 + */ +public class TopicExpiredConfig { + private Integer minExpiredDay = 30; + + private List ignoreClusterIdList = new ArrayList<>(); + + public Integer getMinExpiredDay() { + return minExpiredDay; + } + + public void setMinExpiredDay(Integer minExpiredDay) { + this.minExpiredDay = minExpiredDay; + } + + public List getIgnoreClusterIdList() { + return ignoreClusterIdList; + } + + public void setIgnoreClusterIdList(List ignoreClusterIdList) { + this.ignoreClusterIdList = ignoreClusterIdList; + } + + @Override + public String toString() { + return "TopicExpiredConfig{" + + "minExpiredDay=" + minExpiredDay + + ", ignoreClusterIdList=" + ignoreClusterIdList + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/TopicInsufficientPartitionConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/TopicInsufficientPartitionConfig.java new file mode 100644 index 00000000..d954c6d3 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/config/expert/TopicInsufficientPartitionConfig.java @@ -0,0 +1,50 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.config.expert; + +import java.util.ArrayList; +import java.util.List; + +/** + * 专家服务-Topic分区不足配置 + * @author zengqiao + * @date 20/8/23 + */ +public class TopicInsufficientPartitionConfig { + private Long maxBytesInPerPartitionUnitB = 3 * 1024 * 1024L; + + private Long minTopicBytesInUnitB = 3 * 1024 * 1024L; + + private List ignoreClusterIdList = new ArrayList<>(); + + public Long getMaxBytesInPerPartitionUnitB() { + return maxBytesInPerPartitionUnitB; + } + + public void setMaxBytesInPerPartitionUnitB(Long maxBytesInPerPartitionUnitB) { + this.maxBytesInPerPartitionUnitB = maxBytesInPerPartitionUnitB; + } + + public Long getMinTopicBytesInUnitB() { + return minTopicBytesInUnitB; + } + + public void setMinTopicBytesInUnitB(Long minTopicBytesInUnitB) { + this.minTopicBytesInUnitB = minTopicBytesInUnitB; + } + + public List getIgnoreClusterIdList() { + return ignoreClusterIdList; + } + + public void setIgnoreClusterIdList(List ignoreClusterIdList) { + this.ignoreClusterIdList = ignoreClusterIdList; + } + + @Override + public String toString() { + return "TopicInsufficientPartitionConfig{" + + "maxBytesInPerPartitionUnitB=" + maxBytesInPerPartitionUnitB + + ", minTopicBytesInUnitB=" + minTopicBytesInUnitB + + ", ignoreClusterIdList=" + ignoreClusterIdList + + '}'; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/consumer/ConsumeDetailDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/consumer/ConsumeDetailDTO.java similarity index 94% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/consumer/ConsumeDetailDTO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/consumer/ConsumeDetailDTO.java index 66546d84..a40484e4 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/consumer/ConsumeDetailDTO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/consumer/ConsumeDetailDTO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto.consumer; +package com.xiaojukeji.kafka.manager.common.entity.ao.consumer; /** * @author zengqiao diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/consumer/ConsumerGroupDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/consumer/ConsumerGroupDTO.java similarity index 65% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/consumer/ConsumerGroupDTO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/consumer/ConsumerGroupDTO.java index 072672f6..e09f93e8 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/consumer/ConsumerGroupDTO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/consumer/ConsumerGroupDTO.java @@ -1,7 +1,8 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto.consumer; +package com.xiaojukeji.kafka.manager.common.entity.ao.consumer; -import com.xiaojukeji.kafka.manager.common.constant.OffsetStoreLocation; +import com.xiaojukeji.kafka.manager.common.bizenum.OffsetLocationEnum; +import java.util.List; import java.util.Objects; /** @@ -14,11 +15,17 @@ public class ConsumerGroupDTO { private String consumerGroup; - private OffsetStoreLocation offsetStoreLocation; + private List appIdList; - public ConsumerGroupDTO(Long clusterId, String consumerGroup, OffsetStoreLocation offsetStoreLocation) { + private OffsetLocationEnum offsetStoreLocation; + + public ConsumerGroupDTO(Long clusterId, + String consumerGroup, + List appIdList, + OffsetLocationEnum offsetStoreLocation) { this.clusterId = clusterId; this.consumerGroup = consumerGroup; + this.appIdList = appIdList; this.offsetStoreLocation = offsetStoreLocation; } @@ -38,14 +45,32 @@ public class ConsumerGroupDTO { this.consumerGroup = consumerGroup; } - public OffsetStoreLocation getOffsetStoreLocation() { + public List getAppIdList() { + return appIdList; + } + + public void setAppIdList(List appIdList) { + this.appIdList = appIdList; + } + + public OffsetLocationEnum getOffsetStoreLocation() { return offsetStoreLocation; } - public void setOffsetStoreLocation(OffsetStoreLocation offsetStoreLocation) { + public void setOffsetStoreLocation(OffsetLocationEnum offsetStoreLocation) { this.offsetStoreLocation = offsetStoreLocation; } + @Override + public String toString() { + return "ConsumerGroupDTO{" + + "clusterId=" + clusterId + + ", consumerGroup='" + consumerGroup + '\'' + + ", appIdList=" + appIdList + + ", offsetStoreLocation=" + offsetStoreLocation + + '}'; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -64,13 +89,4 @@ public class ConsumerGroupDTO { public int hashCode() { return Objects.hash(clusterId, consumerGroup, offsetStoreLocation); } - - @Override - public String toString() { - return "ConsumerGroupDTO{" + - "clusterId=" + clusterId + - ", consumerGroup='" + consumerGroup + '\'' + - ", offsetStoreLocation=" + offsetStoreLocation + - '}'; - } } diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicAnomalyFlow.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicAnomalyFlow.java new file mode 100644 index 00000000..558636d9 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicAnomalyFlow.java @@ -0,0 +1,90 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.expert; + +/** + * @author zengqiao + * @date 20/3/30 + */ +public class TopicAnomalyFlow { + private Long clusterId; + + private String clusterName; + + private String topicName; + + private Double bytesIn; + + private Double bytesInIncr; + + private Double iops; + + private Double iopsIncr; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Double getBytesIn() { + return bytesIn; + } + + public void setBytesIn(Double bytesIn) { + this.bytesIn = bytesIn; + } + + public Double getBytesInIncr() { + return bytesInIncr; + } + + public void setBytesInIncr(Double bytesInIncr) { + this.bytesInIncr = bytesInIncr; + } + + public Double getIops() { + return iops; + } + + public void setIops(Double iops) { + this.iops = iops; + } + + public Double getIopsIncr() { + return iopsIncr; + } + + public void setIopsIncr(Double iopsIncr) { + this.iopsIncr = iopsIncr; + } + + @Override + public String toString() { + return "AnomalyFlowTopicDTO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", bytesIn=" + bytesIn + + ", bytesInIncr=" + bytesInIncr + + ", iops=" + iops + + ", iopsIncr=" + iopsIncr + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicInsufficientPartition.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicInsufficientPartition.java new file mode 100644 index 00000000..1199d9c2 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicInsufficientPartition.java @@ -0,0 +1,111 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.expert; + +import com.xiaojukeji.kafka.manager.common.entity.pojo.ClusterDO; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/3/30 + */ +public class TopicInsufficientPartition { + private ClusterDO clusterDO; + + private String topicName; + + private Integer presentPartitionNum; + + private Integer suggestedPartitionNum; + + private List maxAvgBytesInList; + + private Double bytesInPerPartition; + + private List brokerIdList; + + public TopicInsufficientPartition( + ClusterDO clusterDO, + String topicName, + Integer presentPartitionNum, + Integer suggestedPartitionNum, + List maxAvgBytesInList, + Double bytesInPerPartition, + List brokerIdList) { + this.clusterDO = clusterDO; + this.topicName = topicName; + this.presentPartitionNum = presentPartitionNum; + this.suggestedPartitionNum = suggestedPartitionNum; + this.maxAvgBytesInList = maxAvgBytesInList; + this.bytesInPerPartition = bytesInPerPartition; + this.brokerIdList = brokerIdList; + } + + public ClusterDO getClusterDO() { + return clusterDO; + } + + public void setClusterDO(ClusterDO clusterDO) { + this.clusterDO = clusterDO; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getPresentPartitionNum() { + return presentPartitionNum; + } + + public void setPresentPartitionNum(Integer presentPartitionNum) { + this.presentPartitionNum = presentPartitionNum; + } + + public Integer getSuggestedPartitionNum() { + return suggestedPartitionNum; + } + + public void setSuggestedPartitionNum(Integer suggestedPartitionNum) { + this.suggestedPartitionNum = suggestedPartitionNum; + } + + public List getMaxAvgBytesInList() { + return maxAvgBytesInList; + } + + public void setMaxAvgBytesInList(List maxAvgBytesInList) { + this.maxAvgBytesInList = maxAvgBytesInList; + } + + public Double getBytesInPerPartition() { + return bytesInPerPartition; + } + + public void setBytesInPerPartition(Double bytesInPerPartition) { + this.bytesInPerPartition = bytesInPerPartition; + } + + public List getBrokerIdList() { + return brokerIdList; + } + + public void setBrokerIdList(List brokerIdList) { + this.brokerIdList = brokerIdList; + } + + @Override + public String toString() { + return "TopicInsufficientPartition{" + + "clusterDO=" + clusterDO + + ", topicName='" + topicName + '\'' + + ", presentPartitionNum=" + presentPartitionNum + + ", suggestedPartitionNum=" + suggestedPartitionNum + + ", maxAvgBytesInList=" + maxAvgBytesInList + + ", bytesInPerPartition=" + bytesInPerPartition + + ", brokerIdList=" + brokerIdList + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicRegionHot.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicRegionHot.java new file mode 100644 index 00000000..17f2f392 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/expert/TopicRegionHot.java @@ -0,0 +1,70 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.expert; + +import com.xiaojukeji.kafka.manager.common.entity.pojo.ClusterDO; + +import java.util.Map; + +/** + * Region内热点Topic + * @author zengqiao + * @date 20/3/27 + */ +public class TopicRegionHot { + private ClusterDO clusterDO; + + private String topicName; + + private Long retentionTime; + + private Map brokerIdPartitionNumMap; + + public TopicRegionHot(ClusterDO clusterDO, String topicName, Long retentionTime, Map + brokerIdPartitionNumMap) { + this.clusterDO = clusterDO; + this.topicName = topicName; + this.retentionTime = retentionTime; + this.brokerIdPartitionNumMap = brokerIdPartitionNumMap; + } + + public ClusterDO getClusterDO() { + return clusterDO; + } + + public void setClusterDO(ClusterDO clusterDO) { + this.clusterDO = clusterDO; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Long getRetentionTime() { + return retentionTime; + } + + public void setRetentionTime(Long retentionTime) { + this.retentionTime = retentionTime; + } + + public Map getBrokerIdPartitionNumMap() { + return brokerIdPartitionNumMap; + } + + public void setBrokerIdPartitionNumMap(Map brokerIdPartitionNumMap) { + this.brokerIdPartitionNumMap = brokerIdPartitionNumMap; + } + + @Override + public String toString() { + return "ExpertRegionTopicHot{" + + "clusterDO=" + clusterDO + + ", topicName='" + topicName + '\'' + + ", retentionTime=" + retentionTime + + ", brokerIdPartitionNumMap=" + brokerIdPartitionNumMap + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/AppRateConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/AppRateConfig.java new file mode 100644 index 00000000..1ed045e4 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/AppRateConfig.java @@ -0,0 +1,30 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.gateway; + +/** + * @author zengqiao + * @date 20/7/29 + */ +public class AppRateConfig extends BaseGatewayConfig { + private Long appRateLimit; + + public AppRateConfig(Long version, Long appRateLimit) { + this.version = version; + this.appRateLimit = appRateLimit; + } + + public Long getAppRateLimit() { + return appRateLimit; + } + + public void setAppRateLimit(Long appRateLimit) { + this.appRateLimit = appRateLimit; + } + + @Override + public String toString() { + return "AppRateConfig{" + + "appRateLimit=" + appRateLimit + + ", version=" + version + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/BaseGatewayConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/BaseGatewayConfig.java new file mode 100644 index 00000000..528eb214 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/BaseGatewayConfig.java @@ -0,0 +1,24 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.gateway; + +/** + * @author zengqiao + * @date 20/7/29 + */ +public class BaseGatewayConfig { + protected Long version; + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + @Override + public String toString() { + return "GatewayConfig{" + + "version=" + version + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/IpRateConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/IpRateConfig.java new file mode 100644 index 00000000..06c6cfbb --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/IpRateConfig.java @@ -0,0 +1,30 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.gateway; + +/** + * @author zengqiao + * @date 20/7/29 + */ +public class IpRateConfig extends BaseGatewayConfig { + private Long ipRateLimit; + + public IpRateConfig(Long version, Long ipRateLimit) { + this.version = version; + this.ipRateLimit = ipRateLimit; + } + + public Long getIpRateLimit() { + return ipRateLimit; + } + + public void setIpRateLimit(Long ipRateLimit) { + this.ipRateLimit = ipRateLimit; + } + + @Override + public String toString() { + return "IpRateConfig{" + + "ipRateLimit=" + ipRateLimit + + ", version=" + version + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/KafkaBootstrapServerConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/KafkaBootstrapServerConfig.java new file mode 100644 index 00000000..4b00c893 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/KafkaBootstrapServerConfig.java @@ -0,0 +1,33 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.gateway; + +import java.util.List; +import java.util.Map; + +/** + * @author zengqiao + * @date 20/7/29 + */ +public class KafkaBootstrapServerConfig extends BaseGatewayConfig { + private Map> clusterIdBootstrapServersMap; + + public KafkaBootstrapServerConfig(Long version, Map> clusterIdBootstrapServersMap) { + this.version = version; + this.clusterIdBootstrapServersMap = clusterIdBootstrapServersMap; + } + + public Map> getClusterIdBootstrapServersMap() { + return clusterIdBootstrapServersMap; + } + + public void setClusterIdBootstrapServersMap(Map> clusterIdBootstrapServersMap) { + this.clusterIdBootstrapServersMap = clusterIdBootstrapServersMap; + } + + @Override + public String toString() { + return "KafkaBootstrapServerConfig{" + + "clusterIdBootstrapServersMap=" + clusterIdBootstrapServersMap + + ", version=" + version + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/RequestQueueConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/RequestQueueConfig.java new file mode 100644 index 00000000..ff2f2184 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/RequestQueueConfig.java @@ -0,0 +1,30 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.gateway; + +/** + * @author zengqiao + * @date 20/7/29 + */ +public class RequestQueueConfig extends BaseGatewayConfig { + private Long maxRequestQueueSize; + + public RequestQueueConfig(Long version, Long maxRequestQueueSize) { + this.version = version; + this.maxRequestQueueSize = maxRequestQueueSize; + } + + public Long getMaxRequestQueueSize() { + return maxRequestQueueSize; + } + + public void setMaxRequestQueueSize(Long maxRequestQueueSize) { + this.maxRequestQueueSize = maxRequestQueueSize; + } + + @Override + public String toString() { + return "RequestQueueConfig{" + + "maxRequestQueueSize=" + maxRequestQueueSize + + ", version=" + version + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/SpRateConfig.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/SpRateConfig.java new file mode 100644 index 00000000..15f21cf9 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/SpRateConfig.java @@ -0,0 +1,32 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.gateway; + +import java.util.Map; + +/** + * @author zengqiao + * @date 20/7/29 + */ +public class SpRateConfig extends BaseGatewayConfig { + private Map spRateMap; + + public SpRateConfig(Long version, Map spRateMap) { + this.version = version; + this.spRateMap = spRateMap; + } + + public Map getSpRateMap() { + return spRateMap; + } + + public void setSpRateMap(Map spRateMap) { + this.spRateMap = spRateMap; + } + + @Override + public String toString() { + return "SpRateConfig{" + + "spRateMap=" + spRateMap + + ", version=" + version + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/TopicQuota.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/TopicQuota.java new file mode 100644 index 00000000..7b3bc979 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/gateway/TopicQuota.java @@ -0,0 +1,68 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.gateway; + +/** + * @author zhongyuankai + * @date 2020/4/27 + */ +public class TopicQuota { + private String appId; + + private Long clusterId; + + private String topicName; + + private Long produceQuota; + + private Long consumeQuota; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Long getProduceQuota() { + return produceQuota; + } + + public void setProduceQuota(Long produceQuota) { + this.produceQuota = produceQuota; + } + + public Long getConsumeQuota() { + return consumeQuota; + } + + public void setConsumeQuota(Long consumeQuota) { + this.consumeQuota = consumeQuota; + } + + @Override + public String toString() { + return "TopicQuota{" + + "appId='" + appId + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", produceQuota=" + produceQuota + + ", consumeQuota=" + consumeQuota + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/reassign/ReassignStatus.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/reassign/ReassignStatus.java new file mode 100644 index 00000000..3e9ec3cb --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/reassign/ReassignStatus.java @@ -0,0 +1,130 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.reassign; + +import com.xiaojukeji.kafka.manager.common.bizenum.TaskStatusReassignEnum; +import com.xiaojukeji.kafka.manager.common.zookeeper.znode.ReassignmentElemData; +import kafka.common.TopicAndPartition; + +import java.util.List; +import java.util.Map; + +/** + * @author zengqiao + * @date 20/5/14 + */ +public class ReassignStatus { + private Long subTaskId; + + private Long clusterId; + + private String clusterName; + + private String topicName; + + private Integer status; + + private Long realThrottle; + + private Long maxThrottle; + + private Long minThrottle; + + private List reassignList; + + private Map reassignStatusMap; + + public Long getSubTaskId() { + return subTaskId; + } + + public void setSubTaskId(Long subTaskId) { + this.subTaskId = subTaskId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Long getRealThrottle() { + return realThrottle; + } + + public void setRealThrottle(Long realThrottle) { + this.realThrottle = realThrottle; + } + + public Long getMaxThrottle() { + return maxThrottle; + } + + public void setMaxThrottle(Long maxThrottle) { + this.maxThrottle = maxThrottle; + } + + public Long getMinThrottle() { + return minThrottle; + } + + public void setMinThrottle(Long minThrottle) { + this.minThrottle = minThrottle; + } + + public List getReassignList() { + return reassignList; + } + + public void setReassignList(List reassignList) { + this.reassignList = reassignList; + } + + public Map getReassignStatusMap() { + return reassignStatusMap; + } + + public void setReassignStatusMap(Map reassignStatusMap) { + this.reassignStatusMap = reassignStatusMap; + } + + @Override + public String toString() { + return "ReassignStatus{" + + "subTaskId=" + subTaskId + + ", clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", status=" + status + + ", realThrottle=" + realThrottle + + ", maxThrottle=" + maxThrottle + + ", minThrottle=" + minThrottle + + ", reassignList=" + reassignList + + ", reassignStatusMap=" + reassignStatusMap + + '}'; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/consumer/ConsumerDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaConsumerMetrics.java similarity index 51% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/consumer/ConsumerDTO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaConsumerMetrics.java index c96c6496..932cd2a1 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/consumer/ConsumerDTO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaConsumerMetrics.java @@ -1,13 +1,12 @@ -package com.xiaojukeji.kafka.manager.common.entity.dto.consumer; +package com.xiaojukeji.kafka.manager.common.entity.ao.remote; -import java.util.Map; +import java.util.List; /** - * Consumer实体类 - * @author tukun - * @date 2015/11/12 + * @author zengqiao + * @date 20/8/25 */ -public class ConsumerDTO { +public class KafkaConsumerMetrics { private Long clusterId; private String topicName; @@ -16,9 +15,11 @@ public class ConsumerDTO { private String location; - private Map partitionOffsetMap; + private Integer partitionNum; - private Map consumerOffsetMap; + private List consumeDetailList; + + private Long createTime; public Long getClusterId() { return clusterId; @@ -52,31 +53,40 @@ public class ConsumerDTO { this.location = location; } - public Map getPartitionOffsetMap() { - return partitionOffsetMap; + public Integer getPartitionNum() { + return partitionNum; } - public void setPartitionOffsetMap(Map partitionOffsetMap) { - this.partitionOffsetMap = partitionOffsetMap; + public void setPartitionNum(Integer partitionNum) { + this.partitionNum = partitionNum; } - public Map getConsumerOffsetMap() { - return consumerOffsetMap; + public List getConsumeDetailList() { + return consumeDetailList; } - public void setConsumerOffsetMap(Map consumerOffsetMap) { - this.consumerOffsetMap = consumerOffsetMap; + public void setConsumeDetailList(List consumeDetailList) { + this.consumeDetailList = consumeDetailList; + } + + public Long getCreateTime() { + return createTime; + } + + public void setCreateTime(Long createTime) { + this.createTime = createTime; } @Override public String toString() { - return "ConsumerDTO{" + + return "KafkaConsumerMetrics{" + "clusterId=" + clusterId + ", topicName='" + topicName + '\'' + ", consumerGroup='" + consumerGroup + '\'' + ", location='" + location + '\'' + - ", partitionOffsetMap=" + partitionOffsetMap + - ", consumerOffsetMap=" + consumerOffsetMap + + ", partitionNum=" + partitionNum + + ", consumeDetailList=" + consumeDetailList + + ", createTime=" + createTime + '}'; } -} +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaConsumerMetricsElem.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaConsumerMetricsElem.java new file mode 100644 index 00000000..678f995f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaConsumerMetricsElem.java @@ -0,0 +1,46 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.remote; + +/** + * @author zengqiao + * @date 20/8/31 + */ +public class KafkaConsumerMetricsElem { + private Integer partitionId; + + private Long partitionOffset; + + private Long consumeOffset; + + public Integer getPartitionId() { + return partitionId; + } + + public void setPartitionId(Integer partitionId) { + this.partitionId = partitionId; + } + + public Long getPartitionOffset() { + return partitionOffset; + } + + public void setPartitionOffset(Long partitionOffset) { + this.partitionOffset = partitionOffset; + } + + public Long getConsumeOffset() { + return consumeOffset; + } + + public void setConsumeOffset(Long consumeOffset) { + this.consumeOffset = consumeOffset; + } + + @Override + public String toString() { + return "KafkaConsumerMetricsElem{" + + "partitionId=" + partitionId + + ", partitionOffset=" + partitionOffset + + ", consumeOffset=" + consumeOffset + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaTopicMetrics.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaTopicMetrics.java new file mode 100644 index 00000000..599384a4 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/remote/KafkaTopicMetrics.java @@ -0,0 +1,79 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.remote; + +/** + * @author zengqiao + * @date 20/8/31 + */ +public class KafkaTopicMetrics { + private Long clusterId; + + private String topic; + + private Integer partitionNum; + + private Double messagesInPerSec; + + private Double bytesInPerSec; + + private Long timestamp; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public Integer getPartitionNum() { + return partitionNum; + } + + public void setPartitionNum(Integer partitionNum) { + this.partitionNum = partitionNum; + } + + public Double getMessagesInPerSec() { + return messagesInPerSec; + } + + public void setMessagesInPerSec(Double messagesInPerSec) { + this.messagesInPerSec = messagesInPerSec; + } + + public Double getBytesInPerSec() { + return bytesInPerSec; + } + + public void setBytesInPerSec(Double bytesInPerSec) { + this.bytesInPerSec = bytesInPerSec; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + @Override + public String toString() { + return "KafkaTopicMetrics{" + + "clusterId=" + clusterId + + ", topic='" + topic + '\'' + + ", partitionNum=" + partitionNum + + ", messagesInPerSec=" + messagesInPerSec + + ", bytesInPerSec=" + bytesInPerSec + + ", timestamp=" + timestamp + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/MineTopicSummary.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/MineTopicSummary.java new file mode 100644 index 00000000..45fffebd --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/MineTopicSummary.java @@ -0,0 +1,123 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; + +/** + * @author zengqiao + * @date 20/5/12 + */ +public class MineTopicSummary { + private Long logicalClusterId; + + private String logicalClusterName; + + private Long physicalClusterId; + + private String topicName; + + private Object bytesIn; + + private Object bytesOut; + + private String appId; + + private String appName; + + private String appPrincipals; + + private Integer access; + + public Long getLogicalClusterId() { + return logicalClusterId; + } + + public void setLogicalClusterId(Long logicalClusterId) { + this.logicalClusterId = logicalClusterId; + } + + public String getLogicalClusterName() { + return logicalClusterName; + } + + public void setLogicalClusterName(String logicalClusterName) { + this.logicalClusterName = logicalClusterName; + } + + public Long getPhysicalClusterId() { + return physicalClusterId; + } + + public void setPhysicalClusterId(Long physicalClusterId) { + this.physicalClusterId = physicalClusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Object getBytesIn() { + return bytesIn; + } + + public void setBytesIn(Object bytesIn) { + this.bytesIn = bytesIn; + } + + public Object getBytesOut() { + return bytesOut; + } + + public void setBytesOut(Object bytesOut) { + this.bytesOut = bytesOut; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppPrincipals() { + return appPrincipals; + } + + public void setAppPrincipals(String appPrincipals) { + this.appPrincipals = appPrincipals; + } + + public Integer getAccess() { + return access; + } + + public void setAccess(Integer access) { + this.access = access; + } + + @Override + public String toString() { + return "MineTopicSummary{" + + "logicalClusterId=" + logicalClusterId + + ", logicalClusterName='" + logicalClusterName + '\'' + + ", physicalClusterId=" + physicalClusterId + + ", topicName='" + topicName + '\'' + + ", bytesIn=" + bytesIn + + ", bytesOut=" + bytesOut + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", appPrincipals='" + appPrincipals + '\'' + + ", access=" + access + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicAppData.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicAppData.java new file mode 100644 index 00000000..a06e9736 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicAppData.java @@ -0,0 +1,123 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; + +/** + * @author zhongyuankai + * @date 2020/6/8 + */ +public class TopicAppData { + private Long clusterId; + + private String topicName; + + private String appId; + + private String appName; + + private String appPrincipals; + + private Long produceQuota; + + private Long consumerQuota; + + private Boolean produceThrottled; + + private Boolean fetchThrottled; + + private Integer access; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppPrincipals() { + return appPrincipals; + } + + public void setAppPrincipals(String appPrincipals) { + this.appPrincipals = appPrincipals; + } + + public Long getProduceQuota() { + return produceQuota; + } + + public void setProduceQuota(Long produceQuota) { + this.produceQuota = produceQuota; + } + + public Long getConsumerQuota() { + return consumerQuota; + } + + public void setConsumerQuota(Long consumerQuota) { + this.consumerQuota = consumerQuota; + } + + public Boolean getProduceThrottled() { + return produceThrottled; + } + + public void setProduceThrottled(Boolean produceThrottled) { + this.produceThrottled = produceThrottled; + } + + public Boolean getFetchThrottled() { + return fetchThrottled; + } + + public void setFetchThrottled(Boolean fetchThrottled) { + this.fetchThrottled = fetchThrottled; + } + + public Integer getAccess() { + return access; + } + + public void setAccess(Integer access) { + this.access = access; + } + + @Override + public String toString() { + return "TopicAppDTO{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", appPrincipals='" + appPrincipals + '\'' + + ", produceQuota=" + produceQuota + + ", consumerQuota=" + consumerQuota + + ", produceThrottled=" + produceThrottled + + ", fetchThrottled=" + fetchThrottled + + ", access=" + access + + '}'; + } +} diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicBasicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBasicDTO.java similarity index 60% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicBasicVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBasicDTO.java index 7fd567d8..9522feee 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicBasicVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBasicDTO.java @@ -1,44 +1,71 @@ -package com.xiaojukeji.kafka.manager.web.vo.topic; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; /** - * Topic的基本信息 - * @author zengqiao - * @date 19/4/1 + * @author arthur + * @date 2018/09/03 */ -@ApiModel(value = "Topic基本信息") -public class TopicBasicVO { - @ApiModelProperty(value = "Topic名称") - private String topicName; +public class TopicBasicDTO { + private Long clusterId; - @ApiModelProperty(value = "分区数") - private Integer partitionNum; + private String appId; - @ApiModelProperty(value = "副本数") - private Integer replicaNum; + private String appName; - @ApiModelProperty(value = "占用Broker数") - private Integer brokerNum; - - @ApiModelProperty(value = "保留时间(ms)") - private Long retentionTime; - - @ApiModelProperty(value = "修改时间") - private Long modifyTime; - - @ApiModelProperty(value = "创建时间") - private Long createTime; - - @ApiModelProperty(value = "负责人") private String principals; - @ApiModelProperty(value = "备注") + private String topicName; + private String description; - @ApiModelProperty(value = "regionNames") - private String regionNames; + private String region; + + private Integer score; + + private String topicCodeC; + + private Integer partitionNum; + + private Integer replicaNum; + + private Integer brokerNum; + + private Long modifyTime; + + private Long createTime; + + private Long retentionTime; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getPrincipals() { + return principals; + } + + public void setPrincipals(String principals) { + this.principals = principals; + } public String getTopicName() { return topicName; @@ -48,6 +75,38 @@ public class TopicBasicVO { this.topicName = topicName; } + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public Integer getScore() { + return score; + } + + public void setScore(Integer score) { + this.score = score; + } + + public String getTopicCodeC() { + return topicCodeC; + } + + public void setTopicCodeC(String topicCodeC) { + this.topicCodeC = topicCodeC; + } + public Integer getPartitionNum() { return partitionNum; } @@ -72,14 +131,6 @@ public class TopicBasicVO { this.brokerNum = brokerNum; } - public Long getRetentionTime() { - return retentionTime; - } - - public void setRetentionTime(Long retentionTime) { - this.retentionTime = retentionTime; - } - public Long getModifyTime() { return modifyTime; } @@ -96,43 +147,32 @@ public class TopicBasicVO { this.createTime = createTime; } - public String getPrincipals() { - return principals; + public Long getRetentionTime() { + return retentionTime; } - public void setPrincipals(String principals) { - this.principals = principals; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getRegionNames() { - return regionNames; - } - - public void setRegionNames(String regionNames) { - this.regionNames = regionNames; + public void setRetentionTime(Long retentionTime) { + this.retentionTime = retentionTime; } @Override public String toString() { - return "TopicBasicVO{" + - "topicName='" + topicName + '\'' + + return "TopicBasicDTO{" + + "clusterId=" + clusterId + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", principals='" + principals + '\'' + + ", topicName='" + topicName + '\'' + + ", description='" + description + '\'' + + ", region='" + region + '\'' + + ", score=" + score + + ", topicCodeC='" + topicCodeC + '\'' + ", partitionNum=" + partitionNum + ", replicaNum=" + replicaNum + ", brokerNum=" + brokerNum + - ", retentionTime=" + retentionTime + ", modifyTime=" + modifyTime + ", createTime=" + createTime + - ", principals='" + principals + '\'' + - ", description='" + description + '\'' + - ", regionNames='" + regionNames + '\'' + + ", retentionTime=" + retentionTime + '}'; } } diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBrokerDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBrokerDTO.java new file mode 100644 index 00000000..75c4638d --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBrokerDTO.java @@ -0,0 +1,81 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; + +import java.util.List; + +/** + * @author zhongyuankai + * @date 20/4/17 + */ +public class TopicBrokerDTO { + private Integer brokerId; + + private String host; + + private Integer partitionNum; + + private List partitionIdList; + + private List leaderPartitionIdList; + + private boolean alive; + + public Integer getBrokerId() { + return brokerId; + } + + public void setBrokerId(Integer brokerId) { + this.brokerId = brokerId; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public Integer getPartitionNum() { + return partitionNum; + } + + public void setPartitionNum(Integer partitionNum) { + this.partitionNum = partitionNum; + } + + public List getPartitionIdList() { + return partitionIdList; + } + + public void setPartitionIdList(List partitionIdList) { + this.partitionIdList = partitionIdList; + } + + public List getLeaderPartitionIdList() { + return leaderPartitionIdList; + } + + public void setLeaderPartitionIdList(List leaderPartitionIdList) { + this.leaderPartitionIdList = leaderPartitionIdList; + } + + public boolean isAlive() { + return alive; + } + + public void setAlive(boolean alive) { + this.alive = alive; + } + + @Override + public String toString() { + return "TopicBrokerDTO{" + + "brokerId=" + brokerId + + ", host='" + host + '\'' + + ", partitionNum=" + partitionNum + + ", partitionIdList=" + partitionIdList + + ", leaderPartitionIdList=" + leaderPartitionIdList + + ", alive=" + alive + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBusinessInfo.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBusinessInfo.java new file mode 100644 index 00000000..978550c8 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicBusinessInfo.java @@ -0,0 +1,68 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; + +/** + * @author zhongyuankai + * @date 20/09/08 + */ +public class TopicBusinessInfo { + private String appId; + + private String appName; + + private String principals; + + private Long clusterId; + + private String topicName; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getPrincipals() { + return principals; + } + + public void setPrincipals(String principals) { + this.principals = principals; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + @Override + public String toString() { + return "TopicBusinessInfoVO{" + + "appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", principals='" + principals + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicConnection.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicConnection.java new file mode 100644 index 00000000..abb40327 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicConnection.java @@ -0,0 +1,90 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; + +/** + * @author zengqiao + * @date 20/4/20 + */ +public class TopicConnection { + private Long clusterId; + + private String topicName; + + private String appId; + + private String ip; + + private String hostname; + + private String clientType; + + private String clientVersion; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public String getClientType() { + return clientType; + } + + public void setClientType(String clientType) { + this.clientType = clientType; + } + + public String getClientVersion() { + return clientVersion; + } + + public void setClientVersion(String clientVersion) { + this.clientVersion = clientVersion; + } + + @Override + public String toString() { + return "TopicConnectionDTO{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", appId='" + appId + '\'' + + ", ip='" + ip + '\'' + + ", hostname='" + hostname + '\'' + + ", clientType='" + clientType + '\'' + + ", clientVersion='" + clientVersion + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicDTO.java new file mode 100644 index 00000000..f64fd49c --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicDTO.java @@ -0,0 +1,101 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; + +/** + * @author zengqiao + * @date 20/5/12 + */ +public class TopicDTO { + private Long logicalClusterId; + + private String logicalClusterName; + + private String topicName; + + private String description; + + private String appId; + + private String appName; + + private String appPrincipals; + + private Boolean needAuth; + + public Long getLogicalClusterId() { + return logicalClusterId; + } + + public void setLogicalClusterId(Long logicalClusterId) { + this.logicalClusterId = logicalClusterId; + } + + public String getLogicalClusterName() { + return logicalClusterName; + } + + public void setLogicalClusterName(String logicalClusterName) { + this.logicalClusterName = logicalClusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppPrincipals() { + return appPrincipals; + } + + public void setAppPrincipals(String appPrincipals) { + this.appPrincipals = appPrincipals; + } + + public Boolean getNeedAuth() { + return needAuth; + } + + public void setNeedAuth(Boolean needAuth) { + this.needAuth = needAuth; + } + + @Override + public String toString() { + return "TopicDTO{" + + "logicalClusterId=" + logicalClusterId + + ", logicalClusterName='" + logicalClusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", description='" + description + '\'' + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", appPrincipals='" + appPrincipals + '\'' + + ", needAuth=" + needAuth + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicExpiredData.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicExpiredData.java new file mode 100644 index 00000000..efa4eac6 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicExpiredData.java @@ -0,0 +1,71 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; + +import com.xiaojukeji.kafka.manager.common.entity.pojo.LogicalClusterDO; +import com.xiaojukeji.kafka.manager.common.entity.pojo.gateway.AppDO; + +/** + * @author zengqiao + * @date 20/9/2 + */ +public class TopicExpiredData { + private Long clusterId; + + private String topicName; + + private LogicalClusterDO logicalClusterDO; + + private AppDO appDO; + + private Integer fetchConnectionNum; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public LogicalClusterDO getLogicalClusterDO() { + return logicalClusterDO; + } + + public void setLogicalClusterDO(LogicalClusterDO logicalClusterDO) { + this.logicalClusterDO = logicalClusterDO; + } + + public AppDO getAppDO() { + return appDO; + } + + public void setAppDO(AppDO appDO) { + this.appDO = appDO; + } + + public Integer getFetchConnectionNum() { + return fetchConnectionNum; + } + + public void setFetchConnectionNum(Integer fetchConnectionNum) { + this.fetchConnectionNum = fetchConnectionNum; + } + + @Override + public String toString() { + return "TopicExpiredData{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", logicalClusterDO=" + logicalClusterDO + + ", appDO=" + appDO + + ", fetchConnectionNum=" + fetchConnectionNum + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicMetricsDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicMetricsDTO.java new file mode 100644 index 00000000..c722b4a9 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicMetricsDTO.java @@ -0,0 +1,147 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; + +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/5/11 + */ +public class TopicMetricsDTO { + @ApiModelProperty(value = "每秒流入消息数") + private Object messagesInPerSec; + + @ApiModelProperty(value = "每秒流入字节数") + private Object bytesInPerSec; + + @ApiModelProperty(value = "每秒流出字节数") + private Object bytesOutPerSec; + + @ApiModelProperty(value = "每秒拒绝字节数") + private Object bytesRejectedPerSec; + + @ApiModelProperty(value = "每秒请求数") + private Object totalProduceRequestsPerSec; + + @ApiModelProperty(value = "appId维度每秒流入消息数") + private Object appIdMessagesInPerSec; + + @ApiModelProperty(value = "appId维度每秒流入字节数") + private Object appIdBytesInPerSec; + + @ApiModelProperty(value = "appId维度每秒流出字节数") + private Object appIdBytesOutPerSec; + + @ApiModelProperty(value = "produce限流") + private Boolean produceThrottled; + + @ApiModelProperty(value = "consume限流") + private Boolean consumeThrottled; + + @ApiModelProperty(value = "创建时间") + private Long gmtCreate; + + public Object getMessagesInPerSec() { + return messagesInPerSec; + } + + public void setMessagesInPerSec(Object messagesInPerSec) { + this.messagesInPerSec = messagesInPerSec; + } + + public Object getBytesInPerSec() { + return bytesInPerSec; + } + + public void setBytesInPerSec(Object bytesInPerSec) { + this.bytesInPerSec = bytesInPerSec; + } + + public Object getBytesOutPerSec() { + return bytesOutPerSec; + } + + public void setBytesOutPerSec(Object bytesOutPerSec) { + this.bytesOutPerSec = bytesOutPerSec; + } + + public Object getBytesRejectedPerSec() { + return bytesRejectedPerSec; + } + + public void setBytesRejectedPerSec(Object bytesRejectedPerSec) { + this.bytesRejectedPerSec = bytesRejectedPerSec; + } + + public Object getTotalProduceRequestsPerSec() { + return totalProduceRequestsPerSec; + } + + public void setTotalProduceRequestsPerSec(Object totalProduceRequestsPerSec) { + this.totalProduceRequestsPerSec = totalProduceRequestsPerSec; + } + + public Object getAppIdMessagesInPerSec() { + return appIdMessagesInPerSec; + } + + public void setAppIdMessagesInPerSec(Object appIdMessagesInPerSec) { + this.appIdMessagesInPerSec = appIdMessagesInPerSec; + } + + public Object getAppIdBytesInPerSec() { + return appIdBytesInPerSec; + } + + public void setAppIdBytesInPerSec(Object appIdBytesInPerSec) { + this.appIdBytesInPerSec = appIdBytesInPerSec; + } + + public Object getAppIdBytesOutPerSec() { + return appIdBytesOutPerSec; + } + + public void setAppIdBytesOutPerSec(Object appIdBytesOutPerSec) { + this.appIdBytesOutPerSec = appIdBytesOutPerSec; + } + + public Boolean getProduceThrottled() { + return produceThrottled; + } + + public void setProduceThrottled(Boolean produceThrottled) { + this.produceThrottled = produceThrottled; + } + + public Boolean getConsumeThrottled() { + return consumeThrottled; + } + + public void setConsumeThrottled(Boolean consumeThrottled) { + this.consumeThrottled = consumeThrottled; + } + + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } + + @Override + public String toString() { + return "TopicMetricsDTO{" + + "messagesInPerSec=" + messagesInPerSec + + ", bytesInPerSec=" + bytesInPerSec + + ", bytesOutPerSec=" + bytesOutPerSec + + ", bytesRejectedPerSec=" + bytesRejectedPerSec + + ", totalProduceRequestsPerSec=" + totalProduceRequestsPerSec + + ", appIdMessagesInPerSec=" + appIdMessagesInPerSec + + ", appIdBytesInPerSec=" + appIdBytesInPerSec + + ", appIdBytesOutPerSec=" + appIdBytesOutPerSec + + ", produceThrottled=" + produceThrottled + + ", consumeThrottled=" + consumeThrottled + + ", gmtCreate=" + gmtCreate + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicOverview.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicOverview.java new file mode 100644 index 00000000..03dd9e37 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicOverview.java @@ -0,0 +1,146 @@ +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; + +/** + * Topic概览信息 + * @author zengqiao + * @date 20/5/14 + */ +public class TopicOverview { + private Long clusterId; + + private String topicName; + + private Integer replicaNum; + + private Integer partitionNum; + + private Long retentionTime; + + private Object byteIn; + + private Object produceRequest; + + private String appName; + + private String appId; + + private String description; + + private Long updateTime; + + private Long logicalClusterId; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getReplicaNum() { + return replicaNum; + } + + public void setReplicaNum(Integer replicaNum) { + this.replicaNum = replicaNum; + } + + public Integer getPartitionNum() { + return partitionNum; + } + + public void setPartitionNum(Integer partitionNum) { + this.partitionNum = partitionNum; + } + + public Long getRetentionTime() { + return retentionTime; + } + + public void setRetentionTime(Long retentionTime) { + this.retentionTime = retentionTime; + } + + public Object getByteIn() { + return byteIn; + } + + public void setByteIn(Object byteIn) { + this.byteIn = byteIn; + } + + public Object getProduceRequest() { + return produceRequest; + } + + public void setProduceRequest(Object produceRequest) { + this.produceRequest = produceRequest; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Long getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Long updateTime) { + this.updateTime = updateTime; + } + + public Long getLogicalClusterId() { + return logicalClusterId; + } + + public void setLogicalClusterId(Long logicalClusterId) { + this.logicalClusterId = logicalClusterId; + } + + @Override + public String toString() { + return "TopicOverview{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", replicaNum=" + replicaNum + + ", partitionNum=" + partitionNum + + ", retentionTime=" + retentionTime + + ", byteIn=" + byteIn + + ", produceRequest=" + produceRequest + + ", appName='" + appName + '\'' + + ", appId='" + appId + '\'' + + ", description='" + description + '\'' + + ", updateTime=" + updateTime + + ", logicalClusterId=" + logicalClusterId + + '}'; + } +} diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicPartitionVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicPartitionDTO.java similarity index 60% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicPartitionVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicPartitionDTO.java index ec33d36f..96e96e50 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicPartitionVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/ao/topic/TopicPartitionDTO.java @@ -1,7 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.topic; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +package com.xiaojukeji.kafka.manager.common.entity.ao.topic; import java.util.List; @@ -9,32 +6,31 @@ import java.util.List; * @author arthur * @date 2017/6/6. */ -@ApiModel(value = "分区信息") -public class TopicPartitionVO { - @ApiModelProperty(value = "分区Id") +public class TopicPartitionDTO { private Integer partitionId; - @ApiModelProperty(value = "offset偏移") - private Long offset; + private Long beginningOffset; + + private Long endOffset; + + private Long msgNum; - @ApiModelProperty(value = "分区leader所在Broker") private Integer leaderBrokerId; - @ApiModelProperty(value = "首选leader的Broker") private Integer preferredBrokerId; - @ApiModelProperty(value = "leaderEpoch") private Integer leaderEpoch; - @ApiModelProperty(value = "replica") private List replicaBrokerIdList; - @ApiModelProperty(value = "ISR") private List isrBrokerIdList; - @ApiModelProperty(value = "True:未同步, False:已同步") private Boolean underReplicated; + private Long logSize; + + private String location; + public Integer getPartitionId() { return partitionId; } @@ -43,12 +39,28 @@ public class TopicPartitionVO { this.partitionId = partitionId; } - public Long getOffset() { - return offset; + public Long getBeginningOffset() { + return beginningOffset; } - public void setOffset(Long offset) { - this.offset = offset; + public void setBeginningOffset(Long beginningOffset) { + this.beginningOffset = beginningOffset; + } + + public Long getEndOffset() { + return endOffset; + } + + public void setEndOffset(Long endOffset) { + this.endOffset = endOffset; + } + + public Long getMsgNum() { + return msgNum; + } + + public void setMsgNum(Long msgNum) { + this.msgNum = msgNum; } public Integer getLeaderBrokerId() { @@ -91,25 +103,45 @@ public class TopicPartitionVO { this.isrBrokerIdList = isrBrokerIdList; } - public boolean isUnderReplicated() { + public Boolean getUnderReplicated() { return underReplicated; } - public void setUnderReplicated(boolean underReplicated) { + public void setUnderReplicated(Boolean underReplicated) { this.underReplicated = underReplicated; } + public Long getLogSize() { + return logSize; + } + + public void setLogSize(Long logSize) { + this.logSize = logSize; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + @Override public String toString() { - return "TopicPartitionVO{" + + return "TopicPartitionDTO{" + "partitionId=" + partitionId + - ", offset=" + offset + + ", beginningOffset=" + beginningOffset + + ", endOffset=" + endOffset + + ", msgNum=" + msgNum + ", leaderBrokerId=" + leaderBrokerId + ", preferredBrokerId=" + preferredBrokerId + ", leaderEpoch=" + leaderEpoch + ", replicaBrokerIdList=" + replicaBrokerIdList + ", isrBrokerIdList=" + isrBrokerIdList + ", underReplicated=" + underReplicated + + ", logSize=" + logSize + + ", location='" + location + '\'' + '}'; } } diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/TopicFavorite.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/ClusterTopicDTO.java similarity index 58% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/TopicFavorite.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/ClusterTopicDTO.java index 066080b0..7a23191d 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/topic/TopicFavorite.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/ClusterTopicDTO.java @@ -1,21 +1,20 @@ -package com.xiaojukeji.kafka.manager.web.model.topic; +package com.xiaojukeji.kafka.manager.common.entity.dto; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; /** * @author zengqiao - * @date 19/7/11 + * @date 20/4/23 */ -@JsonIgnoreProperties(ignoreUnknown = true) -@ApiModel(value = "TopicFavorite", description = "Topic收藏,取消收藏") -public class TopicFavorite { +@ApiModel(description="Topic信息") +public class ClusterTopicDTO { @ApiModelProperty(value = "集群ID") - private Long clusterId; + protected Long clusterId; @ApiModelProperty(value = "Topic名称") - private String topicName; + protected String topicName; public Long getClusterId() { return clusterId; @@ -35,9 +34,17 @@ public class TopicFavorite { @Override public String toString() { - return "TopicFavorite{" + + return "ClusterTopicDTO{" + "clusterId=" + clusterId + ", topicName='" + topicName + '\'' + '}'; } + + public boolean paramLegal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isNull(topicName)) { + return false; + } + return true; + } } \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/config/ConfigDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/config/ConfigDTO.java new file mode 100644 index 00000000..397a8b9a --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/config/ConfigDTO.java @@ -0,0 +1,65 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.config; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/3/20 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(description = "配置") +public class ConfigDTO { + @ApiModelProperty(value = "配置key") + private String configKey; + + @ApiModelProperty(value = "配置value") + private String configValue; + + @ApiModelProperty(value = "备注") + private String configDescription; + + public String getConfigKey() { + return configKey; + } + + public void setConfigKey(String configKey) { + this.configKey = configKey; + } + + public String getConfigValue() { + return configValue; + } + + public void setConfigValue(String configValue) { + this.configValue = configValue; + } + + public String getConfigDescription() { + return configDescription; + } + + public void setConfigDescription(String configDescription) { + this.configDescription = configDescription; + } + + @Override + public String toString() { + return "ConfigDTO{" + + "configKey='" + configKey + '\'' + + ", configValue='" + configValue + '\'' + + ", configDescription='" + configDescription + '\'' + + '}'; + } + + public boolean paramLegal() { + if (ValidateUtils.isExistBlank(configKey) + || ValidateUtils.isBlank(configValue) + || ValidateUtils.isBlank(configDescription)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/KafkaAclSearchDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/KafkaAclSearchDTO.java new file mode 100644 index 00000000..8285cb46 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/KafkaAclSearchDTO.java @@ -0,0 +1,61 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.gateway; + +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/7/7 + */ +public class KafkaAclSearchDTO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "开始时间(ms)") + private Long start; + + @ApiModelProperty(value = "结束时间(ms)") + private Long end; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public Long getStart() { + return start; + } + + public void setStart(Long start) { + this.start = start; + } + + public Long getEnd() { + return end; + } + + public void setEnd(Long end) { + this.end = end; + } + + @Override + public String toString() { + return "KafkaAclSearchDTO{" + + "clusterId=" + clusterId + + ", start=" + start + + ", end=" + end + + '}'; + } + + public boolean paramLegal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isNull(start) + || ValidateUtils.isNull(end)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/KafkaUserSearchDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/KafkaUserSearchDTO.java new file mode 100644 index 00000000..40b9ebb7 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/KafkaUserSearchDTO.java @@ -0,0 +1,51 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.gateway; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/7/7 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(description = "Kafka用户查询") +public class KafkaUserSearchDTO { + @ApiModelProperty(value = "开始时间(ms)") + private Long start; + + @ApiModelProperty(value = "结束时间(ms)") + private Long end; + + public Long getStart() { + return start; + } + + public void setStart(Long start) { + this.start = start; + } + + public Long getEnd() { + return end; + } + + public void setEnd(Long end) { + this.end = end; + } + + @Override + public String toString() { + return "KafkaUserSearchDTO{" + + "start=" + start + + ", end=" + end + + '}'; + } + + public boolean paramLegal() { + if (ValidateUtils.isNullOrLessThanZero(start) || ValidateUtils.isNullOrLessThanZero(end)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/TopicConnectionDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/TopicConnectionDTO.java new file mode 100644 index 00000000..8e270338 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/gateway/TopicConnectionDTO.java @@ -0,0 +1,127 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.gateway; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/7/6 + */ +public class TopicConnectionDTO { + private Long id; + + private Long clusterId; + + private String topicName; + + // producer or consumer + private String type; + + // appId#ip#clientVersion + private String clientInfo; + + private String appId; + + private String ip; + + private String clientVersion; + + private Date gmtCreate; + + private Date gmtModify; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getClientInfo() { + return clientInfo; + } + + public void setClientInfo(String clientInfo) { + this.clientInfo = clientInfo; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getClientVersion() { + return clientVersion; + } + + public void setClientVersion(String clientVersion) { + this.clientVersion = clientVersion; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + @Override + public String toString() { + return "TopicConnectionDTO{" + + "id=" + id + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", type='" + type + '\'' + + ", clientInfo='" + clientInfo + '\'' + + ", appId='" + appId + '\'' + + ", ip='" + ip + '\'' + + ", clientVersion='" + clientVersion + '\'' + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/AppDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/AppDTO.java new file mode 100644 index 00000000..b35e42d8 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/AppDTO.java @@ -0,0 +1,76 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.normal; + +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/5/4 + */ +@ApiModel(description="App信息") +public class AppDTO { + @ApiModelProperty(value="AppId, 不可修改") + private String appId; + + @ApiModelProperty(value="App名称") + private String name; + + @ApiModelProperty(value="App描述") + private String description; + + @ApiModelProperty(value="App负责人") + private String principals; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + 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; + } + + public String getPrincipals() { + return principals; + } + + public void setPrincipals(String principals) { + this.principals = principals; + } + + @Override + public String toString() { + return "AppDTO{" + + "appId='" + appId + '\'' + + ", name='" + name + '\'' + + ", description='" + description + '\'' + + ", principals='" + principals + '\'' + + '}'; + } + + public boolean legal() { + if (ValidateUtils.isBlank(appId) + || ValidateUtils.isBlank(name) + || ValidateUtils.isBlank(principals) + || ValidateUtils.isBlank(description)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/JmxSwitchDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/JmxSwitchDTO.java new file mode 100644 index 00000000..ee6986cb --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/JmxSwitchDTO.java @@ -0,0 +1,126 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.normal; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/8/21 + */ +@ApiModel(description = "JmxSwitch开关") +@JsonIgnoreProperties(ignoreUnknown = true) +public class JmxSwitchDTO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "是否是物理集群ID, True:是, False:否") + private Boolean isPhysicalClusterId; + + @ApiModelProperty(value = "Topic请求你JMX") + private String topicName; + + @ApiModelProperty(value = "Topic请求你JMX") + private Boolean openTopicRequestMetrics; + + @ApiModelProperty(value = "AppTopicJMX") + private Boolean openAppIdTopicMetrics; + + @ApiModelProperty(value = "客户端请求JMX") + private Boolean openClientRequestMetrics; + + @ApiModelProperty(value = "磁盘JMX") + private Boolean openDiskMetrics; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public Boolean getPhysicalClusterId() { + return isPhysicalClusterId; + } + + public void setPhysicalClusterId(Boolean physicalClusterId) { + isPhysicalClusterId = physicalClusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Boolean getOpenTopicRequestMetrics() { + return openTopicRequestMetrics; + } + + public void setOpenTopicRequestMetrics(Boolean openTopicRequestMetrics) { + this.openTopicRequestMetrics = openTopicRequestMetrics; + } + + public Boolean getOpenAppIdTopicMetrics() { + return openAppIdTopicMetrics; + } + + public void setOpenAppIdTopicMetrics(Boolean openAppIdTopicMetrics) { + this.openAppIdTopicMetrics = openAppIdTopicMetrics; + } + + public Boolean getOpenClientRequestMetrics() { + return openClientRequestMetrics; + } + + public void setOpenClientRequestMetrics(Boolean openClientRequestMetrics) { + this.openClientRequestMetrics = openClientRequestMetrics; + } + + public Boolean getOpenDiskMetrics() { + return openDiskMetrics; + } + + public void setOpenDiskMetrics(Boolean openDiskMetrics) { + this.openDiskMetrics = openDiskMetrics; + } + + @Override + public String toString() { + return "JmxSwitchDTO{" + + "clusterId=" + clusterId + + ", isPhysicalClusterId=" + isPhysicalClusterId + + ", topicName='" + topicName + '\'' + + ", openTopicRequestMetrics=" + openTopicRequestMetrics + + ", openAppIdTopicMetrics=" + openAppIdTopicMetrics + + ", openClientRequestMetrics=" + openClientRequestMetrics + + ", openDiskMetrics=" + openDiskMetrics + + '}'; + } + + public boolean paramLegal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isNull(isPhysicalClusterId) + || ValidateUtils.isNull(topicName)) { + return false; + } + + if (ValidateUtils.isNull(openTopicRequestMetrics)) { + openTopicRequestMetrics = Boolean.FALSE; + } + if (ValidateUtils.isNull(openAppIdTopicMetrics)) { + openAppIdTopicMetrics = Boolean.FALSE; + } + if (ValidateUtils.isNull(openClientRequestMetrics)) { + openClientRequestMetrics = Boolean.FALSE; + } + if (ValidateUtils.isNull(openDiskMetrics)) { + openDiskMetrics = Boolean.FALSE; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/KafkaFileDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/KafkaFileDTO.java new file mode 100644 index 00000000..b9337661 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/KafkaFileDTO.java @@ -0,0 +1,143 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.normal; + +import com.xiaojukeji.kafka.manager.common.bizenum.KafkaFileEnum; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.springframework.web.multipart.MultipartFile; + +/** + * @author zengqiao + * @date 20/4/29 + */ +@ApiModel(description = "Kafka文件") +public class KafkaFileDTO { + @ApiModelProperty(value = "ID") + private Long id; + + @ApiModelProperty(value = "集群ID, 创建的时候需要, 修改不需要, 如果是包,则传-1") + private Long clusterId; + + @ApiModelProperty(value = "文件名, 创建时需要, 修改不需要") + private String fileName; + + @ApiModelProperty(value = "文件MD5") + private String fileMd5; + + @ApiModelProperty(value = "文件类型, 创建时需要, 修改不需要") + private Integer fileType; + + @ApiModelProperty(value = "备注") + private String description; + + @ApiModelProperty(value = "上传的文件") + private MultipartFile uploadFile; + + @ApiModelProperty(value = "是更新操作") + private Boolean modify; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getFileMd5() { + return fileMd5; + } + + public void setFileMd5(String fileMd5) { + this.fileMd5 = fileMd5; + } + + public Integer getFileType() { + return fileType; + } + + public void setFileType(Integer fileType) { + this.fileType = fileType; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public MultipartFile getUploadFile() { + return uploadFile; + } + + public void setUploadFile(MultipartFile uploadFile) { + this.uploadFile = uploadFile; + } + + public Boolean getModify() { + return modify; + } + + public void setModify(Boolean modify) { + this.modify = modify; + } + + @Override + public String toString() { + return "KafkaFileDTO{" + + "id=" + id + + ", clusterId=" + clusterId + + ", fileName='" + fileName + '\'' + + ", fileMd5='" + fileMd5 + '\'' + + ", fileType=" + fileType + + ", description='" + description + '\'' + + '}'; + } + + public boolean createParamLegal() { + if (ValidateUtils.isNull(clusterId) || + ValidateUtils.isBlank(fileName) || + ValidateUtils.isNull(fileType) || + ValidateUtils.isNull(fileMd5) || + ValidateUtils.isNull(uploadFile)) { + return false; + } + if (!(fileName.endsWith(KafkaFileEnum.PACKAGE.getSuffix()) + || fileName.endsWith(KafkaFileEnum.SERVER_CONFIG.getSuffix()))) { + // 后缀不对 + return false; + } + if (KafkaFileEnum.PACKAGE.getCode().equals(fileType) && clusterId != -1) { + // 包不属于任何集群 + return false; + } + return true; + } + + public boolean modifyParamLegal() { + if (ValidateUtils.isBlank(fileName) || + ValidateUtils.isNull(fileMd5) || + ValidateUtils.isNull(uploadFile)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/LoginModel.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/LoginDTO.java similarity index 66% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/model/LoginModel.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/LoginDTO.java index 4e4f70ee..0fa5c77c 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/LoginModel.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/LoginDTO.java @@ -1,20 +1,21 @@ -package com.xiaojukeji.kafka.manager.web.model; +package com.xiaojukeji.kafka.manager.common.entity.dto.normal; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import io.swagger.annotations.ApiModel; -import org.springframework.util.StringUtils; /** * @author zengqiao * @date 19/5/3 */ @JsonIgnoreProperties(ignoreUnknown = true) -@ApiModel(value = "LoginModel", description = "登陆") -public class LoginModel { +@ApiModel(description = "登陆") +public class LoginDTO { private String username; private String password; + private String code; + public String getUsername() { return username; } @@ -31,18 +32,20 @@ public class LoginModel { this.password = password; } - @Override - public String toString() { - return "LoginModel{" + - "username='" + username + '\'' + - ", password='" + password + '\'' + - '}'; + public String getCode() { + return code; } - public boolean legal() { - if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { - return false; - } - return true; + public void setCode(String code) { + this.code = code; + } + + @Override + public String toString() { + return "LoginDTO{" + + "username='" + username + '\'' + + ", password='" + password + '\'' + + ", code='" + code + '\'' + + '}'; } } \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicDataSampleDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicDataSampleDTO.java new file mode 100644 index 00000000..82876522 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicDataSampleDTO.java @@ -0,0 +1,100 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.normal; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.constant.TopicSampleConstant; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModelProperty; + +/** + * Topic采样 + * @author zengqiao + * @date 19/4/8 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class TopicDataSampleDTO { + @ApiModelProperty(value = "分区Id") + private Integer partitionId; + + @ApiModelProperty(value = "最大采样条数[必须小于100]") + private Integer maxMsgNum; + + @ApiModelProperty(value = "采样超时时间[必须小于10000]") + private Integer timeout; + + @ApiModelProperty(value = "采样offset") + private Long offset; + + @ApiModelProperty(value = "截断") + private Boolean truncate; + + @ApiModelProperty(value = "是否是集群ID, 默认不是") + private Boolean isPhysicalClusterId; + + public Integer getPartitionId() { + return partitionId; + } + + public void setPartitionId(Integer partitionId) { + this.partitionId = partitionId; + } + + public Integer getMaxMsgNum() { + return maxMsgNum; + } + + public void setMaxMsgNum(Integer maxMsgNum) { + this.maxMsgNum = maxMsgNum; + } + + public Integer getTimeout() { + return timeout; + } + + public void setTimeout(Integer timeout) { + this.timeout = timeout; + } + + public Long getOffset() { + return offset; + } + + public void setOffset(Long offset) { + this.offset = offset; + } + + public Boolean getTruncate() { + return truncate; + } + + public void setTruncate(Boolean truncate) { + this.truncate = truncate; + } + + public Boolean getIsPhysicalClusterId() { + return isPhysicalClusterId; + } + + public void setIsPhysicalClusterId(Boolean isPhysicalClusterId) { + this.isPhysicalClusterId = isPhysicalClusterId; + } + + @Override + public String toString() { + return "TopicDataSampleDTO{" + + "partitionId=" + partitionId + + ", maxMsgNum=" + maxMsgNum + + ", timeout=" + timeout + + ", offset=" + offset + + ", truncate=" + truncate + + ", isPhysicalClusterId=" + isPhysicalClusterId + + '}'; + } + + public void adjustConfig() { + timeout = Math.min(timeout, TopicSampleConstant.MAX_TIMEOUT_UNIT_MS); + maxMsgNum = Math.min(maxMsgNum, TopicSampleConstant.MAX_MSG_NUM); + if (ValidateUtils.isNull(isPhysicalClusterId)) { + isPhysicalClusterId = false; + } + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicModifyDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicModifyDTO.java new file mode 100644 index 00000000..d59b5471 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicModifyDTO.java @@ -0,0 +1,41 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.normal; + +import com.xiaojukeji.kafka.manager.common.entity.dto.ClusterTopicDTO; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/8 + */ +public class TopicModifyDTO extends ClusterTopicDTO { + @ApiModelProperty(value = "描述") + private String description; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "TopicModifyDTO{" + + "description='" + description + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + '}'; + } + + @Override + public boolean paramLegal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isExistBlank(topicName) + || ValidateUtils.isNull(description)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicOffsetResetDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicOffsetResetDTO.java new file mode 100644 index 00000000..0e2aadb0 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicOffsetResetDTO.java @@ -0,0 +1,139 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.normal; + +import com.xiaojukeji.kafka.manager.common.bizenum.OffsetLocationEnum; +import com.xiaojukeji.kafka.manager.common.entity.ao.PartitionOffsetDTO; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * 重置offset + * @author zengqiao + * @date 19/4/8 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class TopicOffsetResetDTO { + @ApiModelProperty(value = "集群Id") + private Long clusterId; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "消费组") + private String consumerGroup; + + @ApiModelProperty(value = "存储位置") + private String location; + + @ApiModelProperty(value = "重置到指定offset") + private List offsetList; + + @ApiModelProperty(value = "重置到指定时间") + private Long timestamp; + + @ApiModelProperty(value = "是否是物理集群ID") + private Boolean isPhysicalClusterId; + + @ApiModelProperty(value = "指定offset的位置(0 不指定,1 最旧的offset,2 最新的offset)") + private Integer offsetPos; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getConsumerGroup() { + return consumerGroup; + } + + public void setConsumerGroup(String consumerGroup) { + this.consumerGroup = consumerGroup; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public List getOffsetList() { + return offsetList; + } + + public void setOffsetList(List offsetList) { + this.offsetList = offsetList; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + public Boolean getIsPhysicalClusterId() { + return isPhysicalClusterId; + } + + public void setIsPhysicalClusterId(Boolean isPhysicalClusterId) { + this.isPhysicalClusterId = isPhysicalClusterId; + } + + public Integer getOffsetPos() { + return offsetPos; + } + + public void setOffsetPos(Integer offsetPos) { + this.offsetPos = offsetPos; + } + + @Override + public String toString() { + return "TopicOffsetResetDTO{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", consumerGroup='" + consumerGroup + '\'' + + ", location='" + location + '\'' + + ", offsetList=" + offsetList + + ", timestamp=" + timestamp + + ", isPhysicalClusterId=" + isPhysicalClusterId + + ", offsetPos=" + offsetPos + + '}'; + } + + public boolean legal() { + if (clusterId == null + || ValidateUtils.isExistBlank(topicName) + || ValidateUtils.isExistBlank(consumerGroup) + || OffsetLocationEnum.getOffsetStoreLocation(location) == null) { + return false; + } + + if (isPhysicalClusterId == null) { + isPhysicalClusterId = false; + } + if (timestamp == null && offsetList == null && ValidateUtils.isNullOrLessThanZero(offsetPos)) { + return false; + } + if (ValidateUtils.isNull(offsetPos)) { + offsetPos = 0; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicRetainDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicRetainDTO.java new file mode 100644 index 00000000..0472a7c0 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/normal/TopicRetainDTO.java @@ -0,0 +1,44 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.normal; + +import com.xiaojukeji.kafka.manager.common.entity.dto.ClusterTopicDTO; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/8 + */ +@ApiModel(description = "Topic延长保留") +public class TopicRetainDTO extends ClusterTopicDTO{ + + @ApiModelProperty(value = "延期天数") + private Integer retainDays; + + public Integer getRetainDays() { + return retainDays; + } + + public void setRetainDays(Integer retainDays) { + this.retainDays = retainDays; + } + + @Override + public String toString() { + return "TopicRetainDTO{" + + "retainDays=" + retainDays + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + '}'; + } + + @Override + public boolean paramLegal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isNull(topicName) + || ValidateUtils.isNull(retainDays)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/KafkaPackageDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/KafkaPackageDTO.java new file mode 100644 index 00000000..86314d8d --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/KafkaPackageDTO.java @@ -0,0 +1,25 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.op; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/26 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(description="集群任务") +public class KafkaPackageDTO { + @ApiModelProperty(value="名称") + private String name; + + @ApiModelProperty(value="文件类型") + private Integer fileType; + + @ApiModelProperty(value="md5") + private String md5; + + @ApiModelProperty(value="描述备注") + private String description; +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/RebalanceModel.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/RebalanceDTO.java similarity index 51% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/model/RebalanceModel.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/RebalanceDTO.java index c988d3e1..29db6bdc 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/RebalanceModel.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/RebalanceDTO.java @@ -1,27 +1,31 @@ -package com.xiaojukeji.kafka.manager.web.model; +package com.xiaojukeji.kafka.manager.common.entity.dto.op; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.bizenum.RebalanceDimensionEnum; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; /** - * rebalance请求参数 * @author zengqiao * @date 19/7/8 */ @JsonIgnoreProperties(ignoreUnknown = true) -@ApiModel(value = "RebalanceModel", description = "rebalance模型") -public class RebalanceModel { - @ApiModelProperty(value = "集群Id") +@ApiModel(description = "优先副本选举") +public class RebalanceDTO { + @ApiModelProperty(value = "clusterId") private Long clusterId; + @ApiModelProperty(value = "RegionId") + private Long regionId; + @ApiModelProperty(value = "brokerId") private Integer brokerId; - @ApiModelProperty(value = "Topic名称") + @ApiModelProperty(value = "TopicName") private String topicName; - @ApiModelProperty(value = "维度[0: 集群维度, 1: broker维度]") + @ApiModelProperty(value = "维度[0: Cluster维度, 1: Region维度, 2:Broker维度, 3:Topic维度]") private Integer dimension; public Long getClusterId() { @@ -32,6 +36,14 @@ public class RebalanceModel { this.clusterId = clusterId; } + public Long getRegionId() { + return regionId; + } + + public void setRegionId(Long regionId) { + this.regionId = regionId; + } + public Integer getBrokerId() { return brokerId; } @@ -58,19 +70,20 @@ public class RebalanceModel { @Override public String toString() { - return "RebalanceModel{" + + return "RebalanceDTO{" + "clusterId=" + clusterId + + ", regionId=" + regionId + ", brokerId=" + brokerId + - ", topicName=" + topicName + + ", topicName='" + topicName + '\'' + ", dimension=" + dimension + '}'; } - public boolean legal() { - if (dimension == null || clusterId == null) { - return false; - } - if (dimension.equals(1) && brokerId == null) { + public boolean paramLegal() { + if (ValidateUtils.isNull(clusterId) + || RebalanceDimensionEnum.REGION.getCode().equals(dimension) && ValidateUtils.isNull(regionId) + || RebalanceDimensionEnum.BROKER.getCode().equals(dimension) && ValidateUtils.isNull(brokerId) + || RebalanceDimensionEnum.TOPIC.getCode().equals(dimension) && ValidateUtils.isNull(topicName) ) { return false; } return true; diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignExecDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignExecDTO.java new file mode 100644 index 00000000..74189544 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignExecDTO.java @@ -0,0 +1,70 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.op.reassign; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.bizenum.TopicReassignActionEnum; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao_cn@163.com + * @date 19/4/17 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(description = "操作迁移任务") +public class ReassignExecDTO { + @ApiModelProperty(value = "任务ID") + private Long taskId; + + @ApiModelProperty(value = "动作[start|modify|cancel]") + private String action; + + @ApiModelProperty(value = "开始时间(开始之后不可修改)") + private Long beginTime; + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public Long getBeginTime() { + return beginTime; + } + + public void setBeginTime(Long beginTime) { + this.beginTime = beginTime; + } + + @Override + public String toString() { + return "ReassignExecDTO{" + + "taskId=" + taskId + + ", action='" + action + '\'' + + ", beginTime=" + beginTime + + '}'; + } + + public boolean paramLegal() { + if (ValidateUtils.isNull(taskId) + || ValidateUtils.isBlank(action)) { + return false; + } + + if (TopicReassignActionEnum.MODIFY.getAction().equals(action) + && ValidateUtils.isNullOrLessThanZero(beginTime)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignExecSubDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignExecSubDTO.java new file mode 100644 index 00000000..52a1d8c9 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignExecSubDTO.java @@ -0,0 +1,92 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.op.reassign; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/6/11 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(description = "操作迁移子任务") +public class ReassignExecSubDTO { + @ApiModelProperty(value = "子任务ID") + private Long subTaskId; + + @ApiModelProperty(value = "动作[modify]") + private String action; + + @ApiModelProperty(value = "当前限流值(B/s), 完成之前可修改") + private Long throttle; + + @ApiModelProperty(value = "限流值上限(B/s), 完成之前可修改") + private Long maxThrottle; + + @ApiModelProperty(value = "限流值下限(B/s), 完成之前可修改") + private Long minThrottle; + + public Long getSubTaskId() { + return subTaskId; + } + + public void setSubTaskId(Long subTaskId) { + this.subTaskId = subTaskId; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public Long getThrottle() { + return throttle; + } + + public void setThrottle(Long throttle) { + this.throttle = throttle; + } + + public Long getMaxThrottle() { + return maxThrottle; + } + + public void setMaxThrottle(Long maxThrottle) { + this.maxThrottle = maxThrottle; + } + + public Long getMinThrottle() { + return minThrottle; + } + + public void setMinThrottle(Long minThrottle) { + this.minThrottle = minThrottle; + } + + @Override + public String toString() { + return "ReassignExecSubDTO{" + + "subTaskId=" + subTaskId + + ", action='" + action + '\'' + + ", throttle=" + throttle + + ", maxThrottle=" + maxThrottle + + ", minThrottle=" + minThrottle + + '}'; + } + + public boolean paramLegal() { + if (ValidateUtils.isNull(subTaskId) + || ValidateUtils.isBlank(action) + || ValidateUtils.isNullOrLessThanZero(throttle) + || ValidateUtils.isNullOrLessThanZero(maxThrottle) + || ValidateUtils.isNullOrLessThanZero(minThrottle) + || maxThrottle < throttle || throttle < minThrottle) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignTopicDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignTopicDTO.java new file mode 100644 index 00000000..59aa0ae6 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/reassign/ReassignTopicDTO.java @@ -0,0 +1,172 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.op.reassign; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * 迁移(Topic迁移/Partition迁移) + * @author zengqiao_cn@163.com + * @date 19/4/9 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(description = "Topic迁移") +public class ReassignTopicDTO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "目标BrokerID列表") + private List brokerIdList; + + @ApiModelProperty(value = "目标RegionID") + private Long regionId; + + @ApiModelProperty(value = "分区ID") + private List partitionIdList; + + @ApiModelProperty(value = "限流值(B/s)") + private Long throttle; + + @ApiModelProperty(value = "限流上限(B/s)") + private Long maxThrottle; + + @ApiModelProperty(value = "限流下限(B/s)") + private Long minThrottle; + + @ApiModelProperty(value = "原本的保存时间(ms)") + private Long originalRetentionTime; + + @ApiModelProperty(value = "迁移时的保存时间(ms)") + private Long reassignRetentionTime; + + @ApiModelProperty(value = "开始时间(ms, 时间戳)") + private Long beginTime; + + @ApiModelProperty(value = "备注") + private String description; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public List getBrokerIdList() { + return brokerIdList; + } + + public void setBrokerIdList(List brokerIdList) { + this.brokerIdList = brokerIdList; + } + + public Long getRegionId() { + return regionId; + } + + public void setRegionId(Long regionId) { + this.regionId = regionId; + } + + public List getPartitionIdList() { + return partitionIdList; + } + + public void setPartitionIdList(List partitionIdList) { + this.partitionIdList = partitionIdList; + } + + public Long getThrottle() { + return throttle; + } + + public void setThrottle(Long throttle) { + this.throttle = throttle; + } + + public Long getMaxThrottle() { + return maxThrottle; + } + + public void setMaxThrottle(Long maxThrottle) { + this.maxThrottle = maxThrottle; + } + + public Long getMinThrottle() { + return minThrottle; + } + + public void setMinThrottle(Long minThrottle) { + this.minThrottle = minThrottle; + } + + public Long getOriginalRetentionTime() { + return originalRetentionTime; + } + + public void setOriginalRetentionTime(Long originalRetentionTime) { + this.originalRetentionTime = originalRetentionTime; + } + + public Long getReassignRetentionTime() { + return reassignRetentionTime; + } + + public void setReassignRetentionTime(Long reassignRetentionTime) { + this.reassignRetentionTime = reassignRetentionTime; + } + + public Long getBeginTime() { + return beginTime; + } + + public void setBeginTime(Long beginTime) { + this.beginTime = beginTime; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean paramLegal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isExistBlank(topicName) + || ValidateUtils.isNullOrLessThanZero(throttle) + || ValidateUtils.isNullOrLessThanZero(maxThrottle) + || ValidateUtils.isNullOrLessThanZero(minThrottle) + || maxThrottle < throttle || throttle < minThrottle + || ValidateUtils.isNullOrLessThanZero(originalRetentionTime) + || ValidateUtils.isNullOrLessThanZero(reassignRetentionTime) + || originalRetentionTime < reassignRetentionTime + || ValidateUtils.isNullOrLessThanZero(beginTime)) { + return false; + } + if (ValidateUtils.isNull(description)) { + description = ""; + } + + if (ValidateUtils.isEmptyList(brokerIdList) && ValidateUtils.isNull(regionId)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicCreationDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicCreationDTO.java new file mode 100644 index 00000000..66c26c5b --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicCreationDTO.java @@ -0,0 +1,138 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.op.topic; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.entity.dto.ClusterTopicDTO; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; +import java.util.Properties; + +/** + * @author huangyiminghappy@163.com, zengqiao + * @date 2019-04-21 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(description = "Topic创建") +public class TopicCreationDTO extends ClusterTopicDTO { + @ApiModelProperty(value = "AppID") + private String appId; + + @ApiModelProperty(value = "分区数") + private Integer partitionNum; + + @ApiModelProperty(value = "副本数") + private Integer replicaNum; + + @ApiModelProperty(value = "消息保存时间(ms)") + private Long retentionTime; + + @ApiModelProperty(value = "brokerId列表") + private List brokerIdList; + + @ApiModelProperty(value = "RegionId") + private Long regionId; + + @ApiModelProperty(value = "备注") + private String description; + + @ApiModelProperty(value = "Topic属性列表") + private Properties properties; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Integer getPartitionNum() { + return partitionNum; + } + + public void setPartitionNum(Integer partitionNum) { + this.partitionNum = partitionNum; + } + + public Integer getReplicaNum() { + return replicaNum; + } + + public void setReplicaNum(Integer replicaNum) { + this.replicaNum = replicaNum; + } + + public Long getRetentionTime() { + return retentionTime; + } + + public void setRetentionTime(Long retentionTime) { + this.retentionTime = retentionTime; + } + + public List getBrokerIdList() { + return brokerIdList; + } + + public void setBrokerIdList(List brokerIdList) { + this.brokerIdList = brokerIdList; + } + + public Long getRegionId() { + return regionId; + } + + public void setRegionId(Long regionId) { + this.regionId = regionId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties properties) { + this.properties = properties; + } + + @Override + public String toString() { + return "TopicCreationDTO{" + + "appId='" + appId + '\'' + + ", partitionNum=" + partitionNum + + ", replicaNum=" + replicaNum + + ", retentionTime=" + retentionTime + + ", brokerIdList=" + brokerIdList + + ", regionId=" + regionId + + ", description='" + description + '\'' + + ", properties='" + properties + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + '}'; + } + + @Override + public boolean paramLegal() { + if (ValidateUtils.isNull(appId) + || ValidateUtils.isNull(clusterId) + || ValidateUtils.isNull(topicName) + || ValidateUtils.isNull(partitionNum) || partitionNum <= 0 + || ValidateUtils.isNull(replicaNum) || replicaNum <= 0 + || ValidateUtils.isNull(retentionTime) || retentionTime <= 0) { + return false; + } + if ((ValidateUtils.isNull(brokerIdList) || brokerIdList.isEmpty()) && ValidateUtils.isNull(regionId)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicDeletionDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicDeletionDTO.java new file mode 100644 index 00000000..735ee857 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicDeletionDTO.java @@ -0,0 +1,44 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.op.topic; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.entity.dto.ClusterTopicDTO; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/2 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(value = "Topic删除") +public class TopicDeletionDTO extends ClusterTopicDTO { + @ApiModelProperty(value = "不强制") + private Boolean unForce; + + public Boolean getUnForce() { + return unForce; + } + + public void setUnForce(Boolean unForce) { + this.unForce = unForce; + } + + @Override + public String toString() { + return "TopicDeletionDTO{" + + "unForce=" + unForce + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + '}'; + } + + public boolean paramLegal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isNull(topicName) + || ValidateUtils.isNull(unForce)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicExpansionDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicExpansionDTO.java new file mode 100644 index 00000000..bb8a5eb8 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicExpansionDTO.java @@ -0,0 +1,71 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.op.topic; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.entity.dto.ClusterTopicDTO; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/1/2 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(value = "Topic扩分区") +public class TopicExpansionDTO extends ClusterTopicDTO { + @ApiModelProperty(value = "新增分区数") + private Integer partitionNum; + + @ApiModelProperty(value = "brokerId列表") + private List brokerIdList; + + @ApiModelProperty(value = "regionId") + private Long regionId; + + public Integer getPartitionNum() { + return partitionNum; + } + + public void setPartitionNum(Integer partitionNum) { + this.partitionNum = partitionNum; + } + + public List getBrokerIdList() { + return brokerIdList; + } + + public void setBrokerIdList(List brokerIdList) { + this.brokerIdList = brokerIdList; + } + + public Long getRegionId() { + return regionId; + } + + public void setRegionId(Long regionId) { + this.regionId = regionId; + } + + @Override + public String toString() { + return "TopicExpandDTO{" + + ", partitionNum=" + partitionNum + + ", brokerIdList=" + brokerIdList + + ", regionId=" + regionId + + '}'; + } + + public boolean paramLegal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isNull(topicName) + || ValidateUtils.isNull(partitionNum) || partitionNum <= 0) { + return false; + } + if (ValidateUtils.isEmptyList(brokerIdList) && ValidateUtils.isNull(regionId)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicModificationDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicModificationDTO.java new file mode 100644 index 00000000..5d03264e --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/op/topic/TopicModificationDTO.java @@ -0,0 +1,85 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.op.topic; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.entity.dto.ClusterTopicDTO; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.Properties; + +/** + * @author zengqiao + * @date 20/4/24 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(value = "Topic修改") +public class TopicModificationDTO extends ClusterTopicDTO { + @ApiModelProperty(value = "AppID") + private String appId; + + @ApiModelProperty(value = "消息保存时间(ms)") + private Long retentionTime; + + @ApiModelProperty(value = "备注") + private String description; + + @ApiModelProperty(value = "Topic属性列表") + private Properties properties; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Long getRetentionTime() { + return retentionTime; + } + + public void setRetentionTime(Long retentionTime) { + this.retentionTime = retentionTime; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties properties) { + this.properties = properties; + } + + @Override + public String toString() { + return "TopicModificationDTO{" + + "appId='" + appId + '\'' + + ", retentionTime=" + retentionTime + + ", description='" + description + '\'' + + ", properties='" + properties + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + '}'; + } + + @Override + public boolean paramLegal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isNull(topicName) + || ValidateUtils.isNull(appId) + || ValidateUtils.isNull(retentionTime) + || ValidateUtils.isNull(description)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/AccountModel.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/AccountDTO.java similarity index 51% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/model/AccountModel.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/AccountDTO.java index a3ac3bf2..db2b0aff 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/AccountModel.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/AccountDTO.java @@ -1,25 +1,24 @@ -package com.xiaojukeji.kafka.manager.web.model; +package com.xiaojukeji.kafka.manager.common.entity.dto.rd; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import org.springframework.util.StringUtils; /** * @author zengqiao * @date 19/5/3 */ -@ApiModel(value = "AccountModel", description = "用户") -public class AccountModel { +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(description = "用户") +public class AccountDTO { @ApiModelProperty(value = "用户名") private String username; - @ApiModelProperty(value = "新密码, 1.创建账号时, 可不传") + @ApiModelProperty(value = "密码") private String password; - @ApiModelProperty(value = "旧密码") - private String oldPassword; - - @ApiModelProperty(value = "角色[0:普通, 1:运维, 2:管理员]") + @ApiModelProperty(value = "角色") private Integer role; public String getUsername() { @@ -30,14 +29,6 @@ public class AccountModel { this.username = username; } - public String getOldPassword() { - return oldPassword; - } - - public void setOldPassword(String oldPassword) { - this.oldPassword = oldPassword; - } - public String getPassword() { return password; } @@ -56,27 +47,20 @@ public class AccountModel { @Override public String toString() { - return "AccountModel{" + + return "AccountDTO{" + "username='" + username + '\'' + - ", oldPassword='" + oldPassword + '\'' + ", password='" + password + '\'' + ", role=" + role + '}'; } - public boolean insertLegal() { - if (StringUtils.isEmpty(username) - || StringUtils.isEmpty(password) + public boolean legal() { + if (ValidateUtils.isNull(username) || !(role == 0 || role == 1 || role == 2)) { return false; } - return true; - } - - public boolean modifyLegal() { - if (StringUtils.isEmpty(username) - || !(role == 0 || role == 1 || role == 2)) { - return false; + if (ValidateUtils.isNull(password)) { + password = ""; } return true; } diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/ClusterDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/ClusterDTO.java new file mode 100644 index 00000000..666ef6f7 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/ClusterDTO.java @@ -0,0 +1,128 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.rd; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/23 + */ +@ApiModel(description = "集群接入&修改") +@JsonIgnoreProperties(ignoreUnknown = true) +public class ClusterDTO { + @ApiModelProperty(value="集群Id, 修改时传") + private Long clusterId; + + @ApiModelProperty(value="集群名称") + private String clusterName; + + @ApiModelProperty(value="ZK地址, 不允许修改") + private String zookeeper; + + @ApiModelProperty(value="bootstrap地址") + private String bootstrapServers; + + @ApiModelProperty(value="kafka版本") + private String kafkaVersion; + + @ApiModelProperty(value="集群类型") + private Integer mode; + + @ApiModelProperty(value="数据中心") + private String idc; + + @ApiModelProperty(value="安全配置参数") + private String securityProperties; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getZookeeper() { + return zookeeper; + } + + public void setZookeeper(String zookeeper) { + this.zookeeper = zookeeper; + } + + public String getBootstrapServers() { + return bootstrapServers; + } + + public void setBootstrapServers(String bootstrapServers) { + this.bootstrapServers = bootstrapServers; + } + + public String getKafkaVersion() { + return kafkaVersion; + } + + public void setKafkaVersion(String kafkaVersion) { + this.kafkaVersion = kafkaVersion; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public Integer getMode() { + return mode; + } + + public void setMode(Integer mode) { + this.mode = mode; + } + + public String getSecurityProperties() { + return securityProperties; + } + + public void setSecurityProperties(String securityProperties) { + this.securityProperties = securityProperties; + } + + @Override + public String toString() { + return "ClusterDTO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", zookeeper='" + zookeeper + '\'' + + ", bootstrapServers='" + bootstrapServers + '\'' + + ", kafkaVersion='" + kafkaVersion + '\'' + + ", idc='" + idc + '\'' + + ", mode='" + mode + '\'' + + ", securityProperties='" + securityProperties + '\'' + + '}'; + } + + public Boolean legal() { + if (ValidateUtils.isNull(clusterName) + || ValidateUtils.isNull(zookeeper) + || ValidateUtils.isNull(idc) + || ValidateUtils.isNull(mode) + || ValidateUtils.isNull(bootstrapServers) + ) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/CustomScheduledTaskDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/CustomScheduledTaskDTO.java new file mode 100644 index 00000000..d7fa2d72 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/CustomScheduledTaskDTO.java @@ -0,0 +1,35 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.rd; + +/** + * @author zengqiao + * @date 20/8/11 + */ +public class CustomScheduledTaskDTO { + private String name; + + private String cron; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCron() { + return cron; + } + + public void setCron(String cron) { + this.cron = cron; + } + + @Override + public String toString() { + return "CustomScheduledTaskDTO{" + + "name='" + name + '\'' + + ", cron='" + cron + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/LogicalClusterDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/LogicalClusterDTO.java new file mode 100644 index 00000000..c3569774 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/LogicalClusterDTO.java @@ -0,0 +1,118 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.rd; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/6/29 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(description = "LogicalClusterDTO") +public class LogicalClusterDTO { + @ApiModelProperty(value = "ID, 更新时必须传") + private Long id; + + @ApiModelProperty(value = "名称") + private String name; + + @ApiModelProperty(value = "集群模式") + private Integer mode; + + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "regionId列表") + private List regionIdList; + + @ApiModelProperty(value = "所属应用ID") + private String appId; + + @ApiModelProperty(value = "备注") + private String description; + + 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; + } + + public Integer getMode() { + return mode; + } + + public void setMode(Integer mode) { + this.mode = mode; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public List getRegionIdList() { + return regionIdList; + } + + public void setRegionIdList(List regionIdList) { + this.regionIdList = regionIdList; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "LogicalClusterDTO{" + + "id=" + id + + ", name='" + name + '\'' + + ", mode=" + mode + + ", clusterId=" + clusterId + + ", regionIdList=" + regionIdList + + ", appId='" + appId + '\'' + + ", description='" + description + '\'' + + '}'; + } + + public boolean legal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isNull(clusterId) + || ValidateUtils.isEmptyList(regionIdList) + || ValidateUtils.isNull(appId) + || ValidateUtils.isNull(mode)) { + return false; + } + description = ValidateUtils.isNull(description)? "": description; + return true; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/OperateRecordDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/OperateRecordDTO.java new file mode 100644 index 00000000..1837ecfc --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/OperateRecordDTO.java @@ -0,0 +1,91 @@ +package com.xiaojukeji.kafka.manager.common.entity.dto.rd; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.bizenum.ModuleEnum; +import com.xiaojukeji.kafka.manager.common.bizenum.OperateEnum; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import io.swagger.annotations.ApiModelProperty; + +import java.util.Date; + +/** + * @author zhongyuankai_i + * @date 20/09/03 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class OperateRecordDTO { + @ApiModelProperty("模块ID") + private Integer moduleId; + + @ApiModelProperty("操作ID") + private Integer operateId; + + @ApiModelProperty("操作人") + private String operator; + + @ApiModelProperty("开始时间") + private Long startTime; + + @ApiModelProperty("结束时间") + private Long endTime; + + public Integer getModuleId() { + return moduleId; + } + + public void setModuleId(Integer moduleId) { + this.moduleId = moduleId; + } + + public Integer getOperateId() { + return operateId; + } + + public void setOperateId(Integer operateId) { + this.operateId = operateId; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public Long getStartTime() { + return startTime; + } + + public void setStartTime(Long startTime) { + this.startTime = startTime; + } + + public Long getEndTime() { + return endTime; + } + + public void setEndTime(Long endTime) { + this.endTime = endTime; + } + + @Override + public String toString() { + return "OperateRecordDTO{" + + "moduleId=" + moduleId + + ", operateId=" + operateId + + ", operator='" + operator + '\'' + + ", startTime=" + startTime + + ", endTime=" + endTime + + '}'; + } + + public boolean legal() { + if (!ModuleEnum.validate(moduleId) || + (!ValidateUtils.isNull(operateId) && OperateEnum.validate(operateId)) + ) { + return false; + } + return true; + } +} diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/RegionModel.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/RegionDTO.java similarity index 53% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/model/RegionModel.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/RegionDTO.java index eddaeba3..708aa3ce 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/model/RegionModel.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/dto/rd/RegionDTO.java @@ -1,9 +1,9 @@ -package com.xiaojukeji.kafka.manager.web.model; +package com.xiaojukeji.kafka.manager.common.entity.dto.rd; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import org.apache.commons.lang.StringUtils; import java.util.List; @@ -13,59 +13,40 @@ import java.util.List; * @date 19/4/3 */ @JsonIgnoreProperties(ignoreUnknown = true) -@ApiModel(value = "RegionModel", description = "创建Region") -public class RegionModel { - @ApiModelProperty(value = "RegionId, 更新时必须传") - private Long regionId; +@ApiModel(description = "RegionDTO") +public class RegionDTO { + @ApiModelProperty(value = "ID, 更新时必须传") + private Long id; + + @ApiModelProperty(value = "名称") + private String name; @ApiModelProperty(value = "集群ID") private Long clusterId; - @ApiModelProperty(value = "regionName名称") - private String regionName; - - @ApiModelProperty(value = "重要级别, 0:普通, 1:重要,2:重要") - private Integer level; - - @ApiModelProperty(value = "状态, -1:废弃 0:正常 1:容量已满") - private Integer status; - @ApiModelProperty(value = "brokerId列表") private List brokerIdList; @ApiModelProperty(value = "备注") private String description; - public Long getRegionId() { - return regionId; + @ApiModelProperty(value = "状态, 0:正常 1:已满") + private Integer status; + + public Long getId() { + return id; } - public void setRegionId(Long regionId) { - this.regionId = regionId; + public void setId(Long id) { + this.id = id; } - public Long getClusterId() { - return clusterId; + public String getName() { + return name; } - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - public String getRegionName() { - return regionName; - } - - public void setRegionName(String regionName) { - this.regionName = regionName; - } - - public Integer getLevel() { - return level; - } - - public void setLevel(Integer level) { - this.level = level; + public void setName(String name) { + this.name = name; } public Integer getStatus() { @@ -76,6 +57,14 @@ public class RegionModel { this.status = status; } + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + public List getBrokerIdList() { return brokerIdList; } @@ -92,29 +81,26 @@ public class RegionModel { this.description = description; } - public boolean legal() { - if (clusterId == null - || StringUtils.isEmpty(regionName) - || level == null - || brokerIdList == null || brokerIdList.isEmpty()) { - return false; - } - if (description == null) { - description = ""; - } - return true; - } - @Override public String toString() { - return "RegionModel{" + - "regionId=" + regionId + + return "RegionDTO{" + + "id=" + id + + ", name='" + name + '\'' + ", clusterId=" + clusterId + - ", regionName='" + regionName + '\'' + - ", level=" + level + - ", status=" + status + ", brokerIdList=" + brokerIdList + ", description='" + description + '\'' + + ", status=" + status + '}'; } + + public boolean legal() { + if (ValidateUtils.isNull(clusterId) + || ValidateUtils.isNull(clusterId) + || ValidateUtils.isEmptyList(brokerIdList) + || ValidateUtils.isNull(status)) { + return false; + } + description = ValidateUtils.isNull(description)? "": description; + return true; + } } \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BaseMetrics.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BaseMetrics.java new file mode 100644 index 00000000..7752e384 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BaseMetrics.java @@ -0,0 +1,159 @@ +package com.xiaojukeji.kafka.manager.common.entity.metrics; + +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import com.xiaojukeji.kafka.manager.common.utils.jmx.JmxConstant; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author zengqiao + * @date 20/6/16 + */ +public class BaseMetrics { + protected Map metricsMap = new HashMap<>(); + + public Map getMetricsMap() { + return metricsMap; + } + + public void setMetricsMap(Map metricsMap) { + this.metricsMap = metricsMap; + } + + @Override + public String toString() { + return "BaseMetrics{" + + "metricsMap=" + metricsMap + + '}'; + } + + public Object getSpecifiedMetrics(String metricsName) { + return metricsMap.get(metricsName); + } + + public T getSpecifiedMetrics(String metricsName, Class cls) { + Object data = metricsMap.get(metricsName); + if (ValidateUtils.isNull(data)) { + return null; + } + return cls.cast(data); + } + + public Double getTotalProduceRequestsPerSecOneMinuteRate(Double defaultValue) { + Object data = metricsMap.get("TotalProduceRequestsPerSecOneMinuteRate"); + if (data == null) { + return defaultValue; + } + return Double.valueOf(data.toString()); + } + + public Double getTotalFetchRequestsPerSecOneMinuteRate(Double defaultValue) { + Object data = metricsMap.get("TotalFetchRequestsPerSecOneMinuteRate"); + if (data == null) { + return defaultValue; + } + return Double.valueOf(data.toString()); + } + + public Double getBytesInPerSecOneMinuteRate(Double defaultValue) { + Object data = metricsMap.get("BytesInPerSecOneMinuteRate"); + if (data == null) { + return defaultValue; + } + return Double.valueOf(data.toString()); + } + + public Double getBytesOutPerSecOneMinuteRate(Double defaultValue) { + Object data = metricsMap.get("BytesOutPerSecOneMinuteRate"); + if (data == null) { + return defaultValue; + } + return Double.valueOf(data.toString()); + } + + public Double getBytesRejectedPerSecOneMinuteRate(Double defaultValue) { + Object data = metricsMap.get("BytesRejectedPerSecOneMinuteRate"); + if (data == null) { + return defaultValue; + } + return Double.valueOf(data.toString()); + } + + public Double getMessagesInPerSecOneMinuteRate(Double defaultValue) { + Object data = metricsMap.get("MessagesInPerSecOneMinuteRate"); + if (data == null) { + return defaultValue; + } + return Double.valueOf(data.toString()); + } + + public void updateCreateTime(Long timestamp) { + metricsMap.put(JmxConstant.CREATE_TIME, timestamp); + } + + public BaseMetrics mergeByAdd(BaseMetrics metrics) { + if (metrics == null) { + return this; + } + for (Map.Entry entry: metrics.metricsMap.entrySet()) { + mergeByAdd(entry.getKey(), entry.getValue()); + } + return this; + } + + public BaseMetrics mergeByAdd(String objectKey, Object objectValue) { + if (objectKey == null || objectValue == null) { + return this; + } + if (!this.metricsMap.containsKey(objectKey)) { + this.metricsMap.put(objectKey, objectValue); + return this; + } + Object object = this.metricsMap.get(objectKey); + if (object instanceof Integer) { + this.metricsMap.put(objectKey, (Integer) objectValue + (Integer) object); + } else if (object instanceof Long) { + this.metricsMap.put(objectKey, (Long) objectValue + (Long) object); + } else if (object instanceof Float) { + this.metricsMap.put(objectKey, (Float) objectValue + (Float) object); + } else if (object instanceof String) { + this.metricsMap.put(objectKey, (String) objectValue + "," + (String) object); + } else { + this.metricsMap.put(objectKey, (Double) objectValue + (Double) object); + } + return this; + } + + public BaseMetrics mergeByMax(BaseMetrics metrics) { + if (metrics == null) { + return this; + } + for (Map.Entry entry: metrics.metricsMap.entrySet()) { + mergeByMax(entry.getKey(), entry.getValue()); + } + return this; + } + + public BaseMetrics mergeByMax(String objectKey, Object objectValue) { + if (objectKey == null || objectValue == null) { + return this; + } + if (!this.metricsMap.containsKey(objectKey)) { + this.metricsMap.put(objectKey, objectValue); + return this; + } + + Object object = this.metricsMap.get(objectKey); + if (object instanceof Integer) { + this.metricsMap.put(objectKey, Math.max((Integer) objectValue, (Integer) object)); + } else if (object instanceof Long) { + this.metricsMap.put(objectKey, Math.max((Long) objectValue, (Long) object)); + } else if (object instanceof Float) { + this.metricsMap.put(objectKey, Math.max((Float) objectValue, (Float) object)); + } else { + this.metricsMap.put(objectKey, Math.max((Double) objectValue, (Double) object)); + } + return this; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BrokerMetrics.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BrokerMetrics.java new file mode 100644 index 00000000..18153544 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/BrokerMetrics.java @@ -0,0 +1,42 @@ +package com.xiaojukeji.kafka.manager.common.entity.metrics; + +/** + * @author zengqiao + * @date 20/6/17 + */ +public class BrokerMetrics extends BaseMetrics { + private Long clusterId; + + private Integer brokerId; + + public BrokerMetrics(Long clusterId, Integer brokerId) { + super(); + this.clusterId = clusterId; + this.brokerId = brokerId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public Integer getBrokerId() { + return brokerId; + } + + public void setBrokerId(Integer brokerId) { + this.brokerId = brokerId; + } + + @Override + public String toString() { + return "BrokerMetrics{" + + "clusterId=" + clusterId + + ", brokerId=" + brokerId + + ", metricsMap=" + metricsMap + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/ClusterMetrics.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/ClusterMetrics.java new file mode 100644 index 00000000..4a977dcd --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/ClusterMetrics.java @@ -0,0 +1,29 @@ +package com.xiaojukeji.kafka.manager.common.entity.metrics; + +/** + * @author zengqiao + * @date 20/6/18 + */ +public class ClusterMetrics extends BaseMetrics { + private Long clusterId; + + public ClusterMetrics(Long clusterId) { + this.clusterId = clusterId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + @Override + public String toString() { + return "ClusterMetrics{" + + "clusterId=" + clusterId + + ", metricsMap=" + metricsMap + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/ConsumerMetrics.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/ConsumerMetrics.java new file mode 100644 index 00000000..60fcc54f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/ConsumerMetrics.java @@ -0,0 +1,106 @@ +package com.xiaojukeji.kafka.manager.common.entity.metrics; + +import java.util.HashMap; +import java.util.Map; + +/** + * Consumer实体类 + * @author tukun + * @date 2015/11/12 + */ +public class ConsumerMetrics { + private Long clusterId; + + private String topicName; + + private String consumerGroup; + + private String location; + + private Map partitionOffsetMap = new HashMap<>(); + + private Map consumeOffsetMap = new HashMap<>(); + + private long timestampUnitMs; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getConsumerGroup() { + return consumerGroup; + } + + public void setConsumerGroup(String consumerGroup) { + this.consumerGroup = consumerGroup; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public Map getPartitionOffsetMap() { + return partitionOffsetMap; + } + + public void setPartitionOffsetMap(Map partitionOffsetMap) { + this.partitionOffsetMap = partitionOffsetMap; + } + + public Map getConsumeOffsetMap() { + return consumeOffsetMap; + } + + public void setConsumeOffsetMap(Map consumeOffsetMap) { + this.consumeOffsetMap = consumeOffsetMap; + } + + public long getTimestampUnitMs() { + return timestampUnitMs; + } + + public void setTimestampUnitMs(long timestampUnitMs) { + this.timestampUnitMs = timestampUnitMs; + } + + public ConsumerMetrics newConsumerMetrics(String consumerGroup) { + ConsumerMetrics consumerMetrics = new ConsumerMetrics(); + consumerMetrics.setConsumerGroup(consumerGroup); + consumerMetrics.setClusterId(this.getClusterId()); + consumerMetrics.setLocation(this.getLocation()); + consumerMetrics.setTopicName(this.getTopicName()); + consumerMetrics.setConsumeOffsetMap(this.getConsumeOffsetMap()); + consumerMetrics.setPartitionOffsetMap(this.getPartitionOffsetMap()); + consumerMetrics.setTimestampUnitMs(this.getTimestampUnitMs()); + return consumerMetrics; + } + + @Override + public String toString() { + return "ConsumerMetrics{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", consumerGroup='" + consumerGroup + '\'' + + ", location='" + location + '\'' + + ", partitionOffsetMap=" + partitionOffsetMap + + ", consumeOffsetMap=" + consumeOffsetMap + + ", timestampUnitMs=" + timestampUnitMs + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicMetrics.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicMetrics.java new file mode 100644 index 00000000..768d7d84 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicMetrics.java @@ -0,0 +1,48 @@ +package com.xiaojukeji.kafka.manager.common.entity.metrics; + +/** + * @author zengqiao + * @date 20/6/17 + */ +public class TopicMetrics extends BaseMetrics { + private String appId; + + private Long clusterId; + + private String topicName; + + public TopicMetrics(Long clusterId, String topicName) { + super(); + this.clusterId = clusterId; + this.topicName = topicName; + } + + public TopicMetrics(String appId, Long clusterId, String topicName) { + super(); + this.appId = appId; + this.clusterId = clusterId; + this.topicName = topicName; + } + + public String getAppId() { + return appId; + } + + public Long getClusterId() { + return clusterId; + } + + public String getTopicName() { + return topicName; + } + + @Override + public String toString() { + return "TopicMetrics{" + + "appId='" + appId + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", metricsMap=" + metricsMap + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicThrottledMetrics.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicThrottledMetrics.java new file mode 100644 index 00000000..0b2afa5e --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/metrics/TopicThrottledMetrics.java @@ -0,0 +1,72 @@ +package com.xiaojukeji.kafka.manager.common.entity.metrics; + +import com.xiaojukeji.kafka.manager.common.bizenum.KafkaClientEnum; + +import java.util.Set; + +/** + * @author zengqiao + * @date 20/5/13 + */ +public class TopicThrottledMetrics { + private String appId; + + private Long clusterId; + + private String topicName; + + private KafkaClientEnum clientType; + + private Set brokerIdSet; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public KafkaClientEnum getClientType() { + return clientType; + } + + public void setClientType(KafkaClientEnum clientType) { + this.clientType = clientType; + } + + public Set getBrokerIdSet() { + return brokerIdSet; + } + + public void setBrokerIdSet(Set brokerIdSet) { + this.brokerIdSet = brokerIdSet; + } + + @Override + public String toString() { + return "TopicThrottledMetrics{" + + "appId='" + appId + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", clientType=" + clientType + + ", brokerIdSet=" + brokerIdSet + + '}'; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/AccountDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/AccountDO.java similarity index 81% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/AccountDO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/AccountDO.java index 387687be..13623941 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/AccountDO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/AccountDO.java @@ -1,10 +1,20 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; /** * @author zengqiao * @date 19/5/3 */ -public class AccountDO extends BaseDO { +public class AccountDO { + protected Long id; + + protected Integer status; + + protected Date gmtCreate; + + protected Date gmtModify; + private String username; private String password; diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BrokerDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/BrokerDO.java similarity index 53% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BrokerDO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/BrokerDO.java index 9d2fd1a9..0eb0ff81 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/BrokerDO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/BrokerDO.java @@ -1,10 +1,20 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; /** * @author zengqiao * @date 19/4/3 */ -public class BrokerDO extends BaseDO { +public class BrokerDO { + private Long id; + + private Integer status; + + private Date gmtCreate; + + private Date gmtModify; + private Long clusterId; private Integer brokerId; @@ -15,6 +25,40 @@ public class BrokerDO extends BaseDO { private Long timestamp; + private Double maxAvgBytesIn; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + public Long getClusterId() { return clusterId; } @@ -55,18 +99,27 @@ public class BrokerDO extends BaseDO { this.timestamp = timestamp; } + public Double getMaxAvgBytesIn() { + return maxAvgBytesIn; + } + + public void setMaxAvgBytesIn(Double maxAvgBytesIn) { + this.maxAvgBytesIn = maxAvgBytesIn; + } + @Override public String toString() { return "BrokerDO{" + - "clusterId=" + clusterId + + "id=" + id + + ", status=" + status + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + ", clusterId=" + clusterId + ", brokerId=" + brokerId + ", host='" + host + '\'' + ", port=" + port + ", timestamp=" + timestamp + - ", id=" + id + - ", status=" + status + - ", gmtCreate=" + gmtCreate + - ", gmtModify=" + gmtModify + + ", maxAvgBytesIn=" + maxAvgBytesIn + '}'; } } diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/BrokerMetricsDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/BrokerMetricsDO.java new file mode 100644 index 00000000..9ebc4514 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/BrokerMetricsDO.java @@ -0,0 +1,70 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/6/17 + */ +public class BrokerMetricsDO { + private Long id; + + private Long clusterId; + + private Integer brokerId; + + private String metrics; + + private Date gmtCreate; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public Integer getBrokerId() { + return brokerId; + } + + public void setBrokerId(Integer brokerId) { + this.brokerId = brokerId; + } + + public String getMetrics() { + return metrics; + } + + public void setMetrics(String metrics) { + this.metrics = metrics; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + @Override + public String toString() { + return "BrokerMetricsDO{" + + "id=" + id + + ", clusterId=" + clusterId + + ", brokerId=" + brokerId + + ", metrics='" + metrics + '\'' + + ", gmtCreate=" + gmtCreate + + '}'; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/ClusterDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterDO.java similarity index 59% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/ClusterDO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterDO.java index 277fd15a..a594af33 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/ClusterDO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterDO.java @@ -1,86 +1,38 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; +package com.xiaojukeji.kafka.manager.common.entity.pojo; import java.util.Date; -public class ClusterDO extends BaseDO{ +/** + * @author zengqiao + * @date 20/4/23 + */ +public class ClusterDO implements Comparable { + private Long id; + + private Integer status; + + private Date gmtCreate; + + private Date gmtModify; + private String clusterName; private String zookeeper; private String bootstrapServers; + private Integer mode; + + private String securityProperties; + private String kafkaVersion; - private Integer alarmFlag; - - private String securityProtocol; - - private String saslMechanism; - - private String saslJaasConfig; - - public String getClusterName() { - return clusterName; + public Long getId() { + return id; } - public void setClusterName(String clusterName) { - this.clusterName = clusterName; - } - - public String getZookeeper() { - return zookeeper; - } - - public void setZookeeper(String zookeeper) { - this.zookeeper = zookeeper; - } - - public String getBootstrapServers() { - return bootstrapServers; - } - - public void setBootstrapServers(String bootstrapServers) { - this.bootstrapServers = bootstrapServers; - } - - public String getKafkaVersion() { - return kafkaVersion; - } - - public void setKafkaVersion(String kafkaVersion) { - this.kafkaVersion = kafkaVersion; - } - - public Integer getAlarmFlag() { - return alarmFlag; - } - - public void setAlarmFlag(Integer alarmFlag) { - this.alarmFlag = alarmFlag; - } - - public String getSecurityProtocol() { - return securityProtocol; - } - - public void setSecurityProtocol(String securityProtocol) { - this.securityProtocol = securityProtocol; - } - - public String getSaslMechanism() { - return saslMechanism; - } - - public void setSaslMechanism(String saslMechanism) { - this.saslMechanism = saslMechanism; - } - - public String getSaslJaasConfig() { - return saslJaasConfig; - } - - public void setSaslJaasConfig(String saslJaasConfig) { - this.saslJaasConfig = saslJaasConfig; + public void setId(Long id) { + this.id = id; } public Integer getStatus() { @@ -107,21 +59,72 @@ public class ClusterDO extends BaseDO{ this.gmtModify = gmtModify; } + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getZookeeper() { + return zookeeper; + } + + public void setZookeeper(String zookeeper) { + this.zookeeper = zookeeper; + } + + public String getBootstrapServers() { + return bootstrapServers; + } + + public void setBootstrapServers(String bootstrapServers) { + this.bootstrapServers = bootstrapServers; + } + + public Integer getMode() { + return mode; + } + + public void setMode(Integer mode) { + this.mode = mode; + } + + public String getSecurityProperties() { + return securityProperties; + } + + public void setSecurityProperties(String securityProperties) { + this.securityProperties = securityProperties; + } + + public String getKafkaVersion() { + return kafkaVersion; + } + + public void setKafkaVersion(String kafkaVersion) { + this.kafkaVersion = kafkaVersion; + } + @Override public String toString() { return "ClusterDO{" + - "clusterName='" + clusterName + '\'' + - ", zookeeper='" + zookeeper + '\'' + - ", bootstrapServers='" + bootstrapServers + '\'' + - ", kafkaVersion='" + kafkaVersion + '\'' + - ", alarmFlag=" + alarmFlag + - ", securityProtocol='" + securityProtocol + '\'' + - ", saslMechanism='" + saslMechanism + '\'' + - ", saslJaasConfig='" + saslJaasConfig + '\'' + - ", id=" + id + + "id=" + id + ", status=" + status + ", gmtCreate=" + gmtCreate + ", gmtModify=" + gmtModify + + ", clusterName='" + clusterName + '\'' + + ", zookeeper='" + zookeeper + '\'' + + ", bootstrapServers='" + bootstrapServers + '\'' + + ", mode=" + mode + + ", securityProperties='" + securityProperties + '\'' + + ", kafkaVersion='" + kafkaVersion + '\'' + '}'; } + + @Override + public int compareTo(ClusterDO clusterDO) { + return this.id.compareTo(clusterDO.id); + } } \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterMetricsDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterMetricsDO.java new file mode 100644 index 00000000..c5c6bcfa --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterMetricsDO.java @@ -0,0 +1,59 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/4/29 + */ +public class ClusterMetricsDO { + private Long id; + + private Date gmtCreate; + + private Long clusterId; + + private String metrics; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getMetrics() { + return metrics; + } + + public void setMetrics(String metrics) { + this.metrics = metrics; + } + + @Override + public String toString() { + return "ClusterMetricsDO{" + + "id=" + id + + ", gmtCreate=" + gmtCreate + + ", clusterId=" + clusterId + + ", metrics='" + metrics + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterTaskDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterTaskDO.java new file mode 100644 index 00000000..5387dd29 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterTaskDO.java @@ -0,0 +1,213 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/4/21 + */ +public class ClusterTaskDO { + private Long id; + + private String uuid; + + private Long clusterId; + + private String taskType; + + private String kafkaPackage; + + private String kafkaPackageMd5; + + private String serverProperties; + + private String serverPropertiesMd5; + + private Long agentTaskId; + + private Long agentRollbackTaskId; + + private String hostList; + + private String pauseHostList; + + private String rollbackHostList; + + private String rollbackPauseHostList; + + private String operator; + + private Integer taskStatus; + + private Date createTime; + + private Date modifyTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTaskType() { + return taskType; + } + + public void setTaskType(String taskType) { + this.taskType = taskType; + } + + public String getKafkaPackage() { + return kafkaPackage; + } + + public void setKafkaPackage(String kafkaPackage) { + this.kafkaPackage = kafkaPackage; + } + + public String getKafkaPackageMd5() { + return kafkaPackageMd5; + } + + public void setKafkaPackageMd5(String kafkaPackageMd5) { + this.kafkaPackageMd5 = kafkaPackageMd5; + } + + public String getServerProperties() { + return serverProperties; + } + + public void setServerProperties(String serverProperties) { + this.serverProperties = serverProperties; + } + + public String getServerPropertiesMd5() { + return serverPropertiesMd5; + } + + public void setServerPropertiesMd5(String serverPropertiesMd5) { + this.serverPropertiesMd5 = serverPropertiesMd5; + } + + public Long getAgentTaskId() { + return agentTaskId; + } + + public void setAgentTaskId(Long agentTaskId) { + this.agentTaskId = agentTaskId; + } + + public Long getAgentRollbackTaskId() { + return agentRollbackTaskId; + } + + public void setAgentRollbackTaskId(Long agentRollbackTaskId) { + this.agentRollbackTaskId = agentRollbackTaskId; + } + + public String getHostList() { + return hostList; + } + + public void setHostList(String hostList) { + this.hostList = hostList; + } + + public String getPauseHostList() { + return pauseHostList; + } + + public void setPauseHostList(String pauseHostList) { + this.pauseHostList = pauseHostList; + } + + public String getRollbackHostList() { + return rollbackHostList; + } + + public void setRollbackHostList(String rollbackHostList) { + this.rollbackHostList = rollbackHostList; + } + + public String getRollbackPauseHostList() { + return rollbackPauseHostList; + } + + public void setRollbackPauseHostList(String rollbackPauseHostList) { + this.rollbackPauseHostList = rollbackPauseHostList; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public Integer getTaskStatus() { + return taskStatus; + } + + public void setTaskStatus(Integer taskStatus) { + this.taskStatus = taskStatus; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Date modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "ClusterTaskDO{" + + "id=" + id + + ", uuid='" + uuid + '\'' + + ", clusterId=" + clusterId + + ", taskType='" + taskType + '\'' + + ", kafkaPackage='" + kafkaPackage + '\'' + + ", kafkaPackageMd5='" + kafkaPackageMd5 + '\'' + + ", serverProperties='" + serverProperties + '\'' + + ", serverPropertiesMd5='" + serverPropertiesMd5 + '\'' + + ", agentTaskId=" + agentTaskId + + ", agentRollbackTaskId=" + agentRollbackTaskId + + ", hostList='" + hostList + '\'' + + ", pauseHostList='" + pauseHostList + '\'' + + ", rollbackHostList='" + rollbackHostList + '\'' + + ", rollbackPauseHostList='" + rollbackPauseHostList + '\'' + + ", operator='" + operator + '\'' + + ", taskStatus=" + taskStatus + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterTaskDetailDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterTaskDetailDO.java new file mode 100644 index 00000000..561ba043 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ClusterTaskDetailDO.java @@ -0,0 +1,103 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/8/28 + */ +public class ClusterTaskDetailDO { + private Long id; + + private Long taskId; + + private String hostname; + + private Integer groupNum; + + private Date execTime; + + private Date rollbackTime; + + private Date createTime; + + private Date modifyTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public Integer getGroupNum() { + return groupNum; + } + + public void setGroupNum(Integer groupNum) { + this.groupNum = groupNum; + } + + public Date getExecTime() { + return execTime; + } + + public void setExecTime(Date execTime) { + this.execTime = execTime; + } + + public Date getRollbackTime() { + return rollbackTime; + } + + public void setRollbackTime(Date rollbackTime) { + this.rollbackTime = rollbackTime; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Date modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "ClusterTaskDetailDO{" + + "id=" + id + + ", taskId=" + taskId + + ", hostname='" + hostname + '\'' + + ", groupNum=" + groupNum + + ", execTime=" + execTime + + ", rollbackTime=" + rollbackTime + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ConfigDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ConfigDO.java new file mode 100644 index 00000000..85da93da --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ConfigDO.java @@ -0,0 +1,92 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/3/19 + */ +public class ConfigDO { + private Long id; + + private Integer status; + + private Date gmtCreate; + + private Date gmtModify; + + private String configKey; + + private String configValue; + + private String configDescription; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + public String getConfigKey() { + return configKey; + } + + public void setConfigKey(String configKey) { + this.configKey = configKey; + } + + public String getConfigValue() { + return configValue; + } + + public void setConfigValue(String configValue) { + this.configValue = configValue; + } + + public String getConfigDescription() { + return configDescription; + } + + public void setConfigDescription(String configDescription) { + this.configDescription = configDescription; + } + + @Override + public String toString() { + return "ConfigDO{" + + "id=" + id + + ", status=" + status + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + ", configKey='" + configKey + '\'' + + ", configValue='" + configValue + '\'' + + ", configDescription='" + configDescription + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/ControllerDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ControllerDO.java similarity index 81% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/ControllerDO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ControllerDO.java index 824e7a85..3b42d4f0 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/ControllerDO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ControllerDO.java @@ -1,10 +1,16 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; /** * @author zengqiao * @date 20/2/28 */ -public class ControllerDO extends BaseEntryDO { +public class ControllerDO { + private Long id; + + private Date gmtCreate; + private Long clusterId; private Integer brokerId; @@ -15,6 +21,22 @@ public class ControllerDO extends BaseEntryDO { private Integer version; + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + public Long getClusterId() { return clusterId; } @@ -59,12 +81,12 @@ public class ControllerDO extends BaseEntryDO { public String toString() { return "ControllerDO{" + "id=" + id + + ", gmtCreate=" + gmtCreate + ", clusterId=" + clusterId + ", brokerId=" + brokerId + ", host='" + host + '\'' + ", timestamp=" + timestamp + ", version=" + version + - ", gmtCreate=" + gmtCreate + '}'; } diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/HeartbeatDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/HeartbeatDO.java new file mode 100644 index 00000000..f7968f73 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/HeartbeatDO.java @@ -0,0 +1,76 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * 心跳 + * @author zengqiao + * @date 20/8/10 + */ +public class HeartbeatDO implements Comparable { + private Long id; + + private String ip; + + private String hostname; + + private Date createTime; + + private Date modifyTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Date modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "HeartbeatDO{" + + "id=" + id + + ", ip='" + ip + '\'' + + ", hostname='" + hostname + '\'' + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + '}'; + } + + @Override + public int compareTo(HeartbeatDO heartbeatDO) { + return this.id.compareTo(heartbeatDO.id); + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/KafkaBillDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/KafkaBillDO.java new file mode 100644 index 00000000..109ecfee --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/KafkaBillDO.java @@ -0,0 +1,103 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/5/12 + */ +public class KafkaBillDO { + private Long id; + + private Long clusterId; + + private String topicName; + + private String principal; + + private Double quota; + + private Double cost; + + private String gmtDay; + + private Date gmtCreate; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getPrincipal() { + return principal; + } + + public void setPrincipal(String principal) { + this.principal = principal; + } + + public Double getQuota() { + return quota; + } + + public void setQuota(Double quota) { + this.quota = quota; + } + + public Double getCost() { + return cost; + } + + public void setCost(Double cost) { + this.cost = cost; + } + + public String getGmtDay() { + return gmtDay; + } + + public void setGmtDay(String gmtDay) { + this.gmtDay = gmtDay; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + @Override + public String toString() { + return "KafkaBillDO{" + + "id=" + id + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", principal='" + principal + '\'' + + ", quota=" + quota + + ", cost=" + cost + + ", gmtDay='" + gmtDay + '\'' + + ", gmtCreate=" + gmtCreate + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/KafkaFileDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/KafkaFileDO.java new file mode 100644 index 00000000..3a99da65 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/KafkaFileDO.java @@ -0,0 +1,114 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zhongyuankai + * @date 2020/5/7 + */ +public class KafkaFileDO { + private Long id; + + private Date gmtCreate; + + private Date gmtModify; + + private Long clusterId; + + private String fileName; + + private String fileMd5; + + private Integer fileType; + + private String description; + + private String operator; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getFileMd5() { + return fileMd5; + } + + public void setFileMd5(String fileMd5) { + this.fileMd5 = fileMd5; + } + + public Integer getFileType() { + return fileType; + } + + public void setFileType(Integer fileType) { + this.fileType = fileType; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + @Override + public String toString() { + return "KafkaFileDO{" + + "id=" + id + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + ", clusterId=" + clusterId + + ", fileName='" + fileName + '\'' + + ", fileMd5='" + fileMd5 + '\'' + + ", fileType=" + fileType + + ", description='" + description + '\'' + + ", operator='" + operator + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/LogicalClusterDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/LogicalClusterDO.java new file mode 100644 index 00000000..d5cb3497 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/LogicalClusterDO.java @@ -0,0 +1,114 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/6/29 + */ +public class LogicalClusterDO { + private Long id; + + private String name; + + private Integer mode; + + private String appId; + + private Long clusterId; + + private String regionList; + + private String description; + + private Date gmtCreate; + + private Date gmtModify; + + 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; + } + + public Integer getMode() { + return mode; + } + + public void setMode(Integer mode) { + this.mode = mode; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getRegionList() { + return regionList; + } + + public void setRegionList(String regionList) { + this.regionList = regionList; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + @Override + public String toString() { + return "LogicalClusterDO{" + + "id=" + id + + ", name='" + name + '\'' + + ", mode=" + mode + + ", appId='" + appId + '\'' + + ", clusterId=" + clusterId + + ", regionList='" + regionList + '\'' + + ", description='" + description + '\'' + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/MonitorRuleDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/MonitorRuleDO.java new file mode 100644 index 00000000..4650dbd7 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/MonitorRuleDO.java @@ -0,0 +1,92 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/5/21 + */ +public class MonitorRuleDO { + private Long id; + + private String name; + + private Long strategyId; + + private String appId; + + private String operator; + + private Date createTime; + + private Date modifyTime; + + 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; + } + + public Long getStrategyId() { + return strategyId; + } + + public void setStrategyId(Long strategyId) { + this.strategyId = strategyId; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Date modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "MonitorRuleDO{" + + "id=" + id + + ", name='" + name + '\'' + + ", strategyId=" + strategyId + + ", appId='" + appId + '\'' + + ", operator='" + operator + '\'' + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OperateRecordDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OperateRecordDO.java new file mode 100644 index 00000000..50b412b8 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OperateRecordDO.java @@ -0,0 +1,103 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zhongyuankai + * @date 20/09/03 + */ +public class OperateRecordDO { + private Long id; + + private Integer moduleId; + + private Integer operateId; + + private String resource; + + private String content; + + private String operator; + + private Date createTime; + + private Date modifyTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getModuleId() { + return moduleId; + } + + public void setModuleId(Integer moduleId) { + this.moduleId = moduleId; + } + + public Integer getOperateId() { + return operateId; + } + + public void setOperateId(Integer operateId) { + this.operateId = operateId; + } + + public String getResource() { + return resource; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Date modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "OperateRecordDO{" + + "id=" + id + + ", moduleId=" + moduleId + + ", operateId=" + operateId + + ", resource='" + resource + '\'' + + ", content='" + content + '\'' + + ", operator='" + operator + '\'' + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + '}'; + } +} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OperationHistoryDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OperationHistoryDO.java similarity index 73% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OperationHistoryDO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OperationHistoryDO.java index 35edffb8..e513b371 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/po/OperationHistoryDO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OperationHistoryDO.java @@ -1,6 +1,16 @@ -package com.xiaojukeji.kafka.manager.common.entity.po; +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/4/29 + */ +public class OperationHistoryDO { + private Long id; + + private Date gmtCreate; -public class OperationHistoryDO extends BaseEntryDO { private Long clusterId; private String topicName; @@ -9,6 +19,22 @@ public class OperationHistoryDO extends BaseEntryDO { private String operation; + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + public Long getClusterId() { return clusterId; } @@ -44,12 +70,12 @@ public class OperationHistoryDO extends BaseEntryDO { @Override public String toString() { return "OperationHistoryDO{" + - "clusterId=" + clusterId + + "id=" + id + + ", gmtCreate=" + gmtCreate + + ", clusterId=" + clusterId + ", topicName='" + topicName + '\'' + ", operator='" + operator + '\'' + ", operation='" + operation + '\'' + - ", id=" + id + - ", gmtCreate=" + gmtCreate + '}'; } diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OrderDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OrderDO.java new file mode 100644 index 00000000..1fa820fc --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/OrderDO.java @@ -0,0 +1,147 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zhongyuankai + * @date 20/4/23 + */ +public class OrderDO { + private Long id; + + private Integer status; + + private Date gmtCreate; + + private Date gmtModify; + + private Integer type; + + private String title; + + private String applicant; + + private String description; + + private String approver; + + private Date gmtHandle; + + private String opinion; + + private String extensions; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getApplicant() { + return applicant; + } + + public void setApplicant(String applicant) { + this.applicant = applicant; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getApprover() { + return approver; + } + + public void setApprover(String approver) { + this.approver = approver; + } + + public Date getGmtHandle() { + return gmtHandle; + } + + public void setGmtHandle(Date gmtHandle) { + this.gmtHandle = gmtHandle; + } + + public String getOpinion() { + return opinion; + } + + public void setOpinion(String opinion) { + this.opinion = opinion; + } + + public String getExtensions() { + return extensions; + } + + public void setExtensions(String extensions) { + this.extensions = extensions; + } + + @Override + public String toString() { + return "OrderDO{" + + "id=" + id + + ", status=" + status + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + ", type=" + type + + ", title='" + title + '\'' + + ", applicant='" + applicant + '\'' + + ", description='" + description + '\'' + + ", approver='" + approver + '\'' + + ", gmtHandle=" + gmtHandle + + ", opinion='" + opinion + '\'' + + ", extensions='" + extensions + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ReassignTaskDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ReassignTaskDO.java new file mode 100644 index 00000000..0eb311a5 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/ReassignTaskDO.java @@ -0,0 +1,225 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * migrate topic task do + * @author zengqiao + * @date 19/4/16 + */ +public class ReassignTaskDO { + private Long id; + + private Integer status; + + private Date gmtCreate; + + private Date gmtModify; + + private Long taskId; + + private Long clusterId; + + private String topicName; + + private String partitions; + + private String reassignmentJson; + + private Long realThrottle; + + private Long maxThrottle; + + private Long minThrottle; + + private Date beginTime; + + private Long originalRetentionTime; + + private Long reassignRetentionTime; + + private String srcBrokers; + + private String destBrokers; + + private String description; + + private String operator; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getPartitions() { + return partitions; + } + + public void setPartitions(String partitions) { + this.partitions = partitions; + } + + public String getReassignmentJson() { + return reassignmentJson; + } + + public void setReassignmentJson(String reassignmentJson) { + this.reassignmentJson = reassignmentJson; + } + + public Long getRealThrottle() { + return realThrottle; + } + + public void setRealThrottle(Long realThrottle) { + this.realThrottle = realThrottle; + } + + public Long getMaxThrottle() { + return maxThrottle; + } + + public void setMaxThrottle(Long maxThrottle) { + this.maxThrottle = maxThrottle; + } + + public Long getMinThrottle() { + return minThrottle; + } + + public void setMinThrottle(Long minThrottle) { + this.minThrottle = minThrottle; + } + + public Date getBeginTime() { + return beginTime; + } + + public void setBeginTime(Date beginTime) { + this.beginTime = beginTime; + } + + public Long getOriginalRetentionTime() { + return originalRetentionTime; + } + + public void setOriginalRetentionTime(Long originalRetentionTime) { + this.originalRetentionTime = originalRetentionTime; + } + + public Long getReassignRetentionTime() { + return reassignRetentionTime; + } + + public void setReassignRetentionTime(Long reassignRetentionTime) { + this.reassignRetentionTime = reassignRetentionTime; + } + + public String getSrcBrokers() { + return srcBrokers; + } + + public void setSrcBrokers(String srcBrokers) { + this.srcBrokers = srcBrokers; + } + + public String getDestBrokers() { + return destBrokers; + } + + public void setDestBrokers(String destBrokers) { + this.destBrokers = destBrokers; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + @Override + public String toString() { + return "ReassignTaskDO{" + + "id=" + id + + ", status=" + status + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + ", taskId=" + taskId + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", partitions='" + partitions + '\'' + + ", reassignmentJson='" + reassignmentJson + '\'' + + ", realThrottle=" + realThrottle + + ", maxThrottle=" + maxThrottle + + ", minThrottle=" + minThrottle + + ", beginTime=" + beginTime + + ", originalRetentionTime=" + originalRetentionTime + + ", reassignRetentionTime=" + reassignRetentionTime + + ", srcBrokers='" + srcBrokers + '\'' + + ", destBrokers='" + destBrokers + '\'' + + ", description='" + description + '\'' + + ", operator='" + operator + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/RegionDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/RegionDO.java new file mode 100644 index 00000000..1f948510 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/RegionDO.java @@ -0,0 +1,137 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +public class RegionDO implements Comparable { + private Long id; + + private Integer status; + + private Date gmtCreate; + + private Date gmtModify; + + private String name; + + private Long clusterId; + + private String brokerList; + + private Long capacity; + + private Long realUsed; + + private Long estimateUsed; + + private String description; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getBrokerList() { + return brokerList; + } + + public void setBrokerList(String brokerList) { + this.brokerList = brokerList; + } + + public Long getCapacity() { + return capacity; + } + + public void setCapacity(Long capacity) { + this.capacity = capacity; + } + + public Long getRealUsed() { + return realUsed; + } + + public void setRealUsed(Long realUsed) { + this.realUsed = realUsed; + } + + public Long getEstimateUsed() { + return estimateUsed; + } + + public void setEstimateUsed(Long estimateUsed) { + this.estimateUsed = estimateUsed; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "RegionDO{" + + "id=" + id + + ", status=" + status + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + ", name='" + name + '\'' + + ", clusterId=" + clusterId + + ", brokerList='" + brokerList + '\'' + + ", capacity=" + capacity + + ", realUsed=" + realUsed + + ", estimateUsed=" + estimateUsed + + ", description='" + description + '\'' + + '}'; + } + + @Override + public int compareTo(RegionDO regionDO) { + return this.id.compareTo(regionDO.id); + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicDO.java new file mode 100644 index 00000000..b4b56712 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicDO.java @@ -0,0 +1,100 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import com.xiaojukeji.kafka.manager.common.entity.dto.op.topic.TopicCreationDTO; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/4/24 + */ +public class TopicDO { + private Long id; + + private Date gmtCreate; + + private Date gmtModify; + + private String appId; + + private Long clusterId; + + private String topicName; + + private String description; + + private Long peakBytesIn; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Long getPeakBytesIn() { + return peakBytesIn; + } + + public void setPeakBytesIn(Long peakBytesIn) { + this.peakBytesIn = peakBytesIn; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + public static TopicDO buildFrom(TopicCreationDTO dto) { + TopicDO topicDO = new TopicDO(); + topicDO.setAppId(dto.getAppId()); + topicDO.setClusterId(dto.getClusterId()); + topicDO.setTopicName(dto.getTopicName()); + topicDO.setDescription(dto.getDescription()); + return topicDO; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicExpiredDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicExpiredDO.java new file mode 100644 index 00000000..f90cadd0 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicExpiredDO.java @@ -0,0 +1,103 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/3/30 + */ +public class TopicExpiredDO { + private Long id; + + private Long clusterId; + + private String topicName; + + private Integer expiredDay; + + private Date gmtRetain; + + private Integer status; + + private Date gmtCreate; + + private Date gmtModify; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getExpiredDay() { + return expiredDay; + } + + public void setExpiredDay(Integer expiredDay) { + this.expiredDay = expiredDay; + } + + public Date getGmtRetain() { + return gmtRetain; + } + + public void setGmtRetain(Date gmtRetain) { + this.gmtRetain = gmtRetain; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + @Override + public String toString() { + return "TopicExpiredDO{" + + "id=" + id + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", expiredDay=" + expiredDay + + ", gmtRetain=" + gmtRetain + + ", status=" + status + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicMetricsDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicMetricsDO.java new file mode 100644 index 00000000..2bc2a25b --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicMetricsDO.java @@ -0,0 +1,81 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/6/17 + */ +public class TopicMetricsDO { + private Long id; + + private String appId; + + private Long clusterId; + + private String topicName; + + private String metrics; + + private Date gmtCreate; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getMetrics() { + return metrics; + } + + public void setMetrics(String metrics) { + this.metrics = metrics; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + @Override + public String toString() { + return "TopicMetricsDO{" + + "id=" + id + + ", appId='" + appId + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", metrics='" + metrics + '\'' + + ", gmtCreate=" + gmtCreate + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicStatisticsDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicStatisticsDO.java new file mode 100644 index 00000000..b52c84f9 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicStatisticsDO.java @@ -0,0 +1,92 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/3/29 + */ +public class TopicStatisticsDO { + private Long id; + + private Date gmtCreate; + + private Long clusterId; + + private String topicName; + + private Long offsetSum; + + private Double maxAvgBytesIn; + + private String gmtDay; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Long getOffsetSum() { + return offsetSum; + } + + public void setOffsetSum(Long offsetSum) { + this.offsetSum = offsetSum; + } + + public Double getMaxAvgBytesIn() { + return maxAvgBytesIn; + } + + public void setMaxAvgBytesIn(Double maxAvgBytesIn) { + this.maxAvgBytesIn = maxAvgBytesIn; + } + + public String getGmtDay() { + return gmtDay; + } + + public void setGmtDay(String gmtDay) { + this.gmtDay = gmtDay; + } + + @Override + public String toString() { + return "TopicStatisticsDO{" + + "id=" + id + + ", gmtCreate=" + gmtCreate + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", offsetSum=" + offsetSum + + ", maxAvgBytesIn=" + maxAvgBytesIn + + ", gmtDay='" + gmtDay + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicThrottledMetricsDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicThrottledMetricsDO.java new file mode 100644 index 00000000..481ae9f8 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/TopicThrottledMetricsDO.java @@ -0,0 +1,92 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo; + +import java.util.Date; + +/** + * @author zhongyuankai + * @date 20/4/3 + */ +public class TopicThrottledMetricsDO { + private Long id; + + private Long clusterId; + + private String topicName; + + private String appId; + + private Integer produceThrottled; + + private Integer fetchThrottled; + + private Date gmtCreate; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Integer getProduceThrottled() { + return produceThrottled; + } + + public void setProduceThrottled(Integer produceThrottled) { + this.produceThrottled = produceThrottled; + } + + public Integer getFetchThrottled() { + return fetchThrottled; + } + + public void setFetchThrottled(Integer fetchThrottled) { + this.fetchThrottled = fetchThrottled; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + @Override + public String toString() { + return "TopicThrottleDO{" + + "id=" + id + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", appId='" + appId + '\'' + + ", produceThrottled=" + produceThrottled + + ", fetchThrottled=" + fetchThrottled + + ", gmtCreate=" + gmtCreate + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/AppDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/AppDO.java new file mode 100644 index 00000000..600c0ac4 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/AppDO.java @@ -0,0 +1,148 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo.gateway; + +import java.util.Date; +import java.util.Random; + +/** + * @author zengqiao + * @date 20/7/29 + */ +public class AppDO { + private static final String ALPHA_NUM = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; + + private Long id; + + private String appId; + + private String name; + + private String password; + + private Integer type; + + private String applicant; + + private String principals; + + private String description; + + private Date createTime; + + private Date modifyTime; + + public static String getAlphaNum() { + return ALPHA_NUM; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getApplicant() { + return applicant; + } + + public void setApplicant(String applicant) { + this.applicant = applicant; + } + + public String getPrincipals() { + return principals; + } + + public void setPrincipals(String principals) { + this.principals = principals; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Date modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "AppDO{" + + "id=" + id + + ", appId='" + appId + '\'' + + ", name='" + name + '\'' + + ", password='" + password + '\'' + + ", type=" + type + + ", applicant='" + applicant + '\'' + + ", principals='" + principals + '\'' + + ", description='" + description + '\'' + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + '}'; + } + + public void generateAppIdAndPassword(Long orderId, String idc) { + this.appId = AppDO.generateAppId(orderId, idc); + + StringBuffer stringBuffer = new StringBuffer(15); + Random random = new Random(); + for(int i = 0; i < 12; i++) { + int index = random.nextInt(ALPHA_NUM.length()); + stringBuffer.append(ALPHA_NUM.charAt(index)); + } + this.password = stringBuffer.toString(); + } + + public static String generateAppId(Long orderId, String idc) { + return String.format("appId_%06d_%s", orderId, idc); + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/AuthorityDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/AuthorityDO.java new file mode 100644 index 00000000..cd999509 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/AuthorityDO.java @@ -0,0 +1,92 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo.gateway; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/7/21 + */ +public class AuthorityDO { + private Long id; + + private String appId; + + private Long clusterId; + + private String topicName; + + private Integer access; + + private Date createTime; + + private Date modifyTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getAccess() { + return access; + } + + public void setAccess(Integer access) { + this.access = access; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Date modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "AuthorityDO{" + + "id=" + id + + ", appId='" + appId + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", access=" + access + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/GatewayConfigDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/GatewayConfigDO.java new file mode 100644 index 00000000..c0e96000 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/GatewayConfigDO.java @@ -0,0 +1,92 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo.gateway; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/7/28 + */ +public class GatewayConfigDO { + private Long id; + + private String type; + + private String name; + + private String value; + + private Long version; + + private Date createTime; + + private Date modifyTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Date modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "GatewayConfigDO{" + + "id=" + id + + ", type='" + type + '\'' + + ", name='" + name + '\'' + + ", value='" + value + '\'' + + ", version=" + version + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/KafkaAclDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/KafkaAclDO.java new file mode 100644 index 00000000..79ca398e --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/KafkaAclDO.java @@ -0,0 +1,92 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo.gateway; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/7/21 + */ +public class KafkaAclDO { + private Long id; + + private String appId; + + private Long clusterId; + + private String topicName; + + private Integer access; + + private Integer operation; + + private Date createTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getAccess() { + return access; + } + + public void setAccess(Integer access) { + this.access = access; + } + + public Integer getOperation() { + return operation; + } + + public void setOperation(Integer operation) { + this.operation = operation; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "KafkaAclDO{" + + "id=" + id + + ", appId='" + appId + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", access=" + access + + ", operation=" + operation + + ", createTime=" + createTime + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/KafkaUserDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/KafkaUserDO.java new file mode 100644 index 00000000..e858e142 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/KafkaUserDO.java @@ -0,0 +1,81 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo.gateway; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/7/21 + */ +public class KafkaUserDO { + private Long id; + + private String appId; + + private String password; + + private Integer userType; + + private Integer operation; + + private Date createTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public Integer getOperation() { + return operation; + } + + public void setOperation(Integer operation) { + this.operation = operation; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "KafkaUserDO{" + + "id=" + id + + ", appId='" + appId + '\'' + + ", password='" + password + '\'' + + ", userType=" + userType + + ", operation=" + operation + + ", createTime=" + createTime + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/TopicConnectionDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/TopicConnectionDO.java new file mode 100644 index 00000000..4707d271 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/TopicConnectionDO.java @@ -0,0 +1,108 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo.gateway; + +import java.util.Date; + +/** + * Topic连接信息 + * @author zengqiao + * @date 20/7/6 + */ +public class TopicConnectionDO { + private Long id; + + private String appId; + + private Long clusterId; + + private String topicName; + + private String type; + + private String ip; + + private String clientVersion; + + private Date createTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getClientVersion() { + return clientVersion; + } + + public void setClientVersion(String clientVersion) { + this.clientVersion = clientVersion; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "TopicConnectionDO{" + + "id=" + id + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", type='" + type + '\'' + + ", appId='" + appId + '\'' + + ", ip='" + ip + '\'' + + ", clientVersion='" + clientVersion + '\'' + + ", createTime=" + createTime + + '}'; + } + + public String uniqueKey() { + return appId + clusterId + topicName + type + ip; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/TopicReportDO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/TopicReportDO.java new file mode 100644 index 00000000..e495cdc6 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/pojo/gateway/TopicReportDO.java @@ -0,0 +1,92 @@ +package com.xiaojukeji.kafka.manager.common.entity.pojo.gateway; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/7/29 + */ +public class TopicReportDO { + private Long id; + + private Long clusterId; + + private String topicName; + + private Date startTime; + + private Date endTime; + + private Date createTime; + + private Date modifyTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Date modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "TopicReportDO{" + + "id=" + id + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountRoleVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountRoleVO.java new file mode 100644 index 00000000..aca8087a --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountRoleVO.java @@ -0,0 +1,46 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.common; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/8/26 + */ +@ApiModel(description = "账号角色信息") +public class AccountRoleVO { + @ApiModelProperty(value = "账号") + private String username; + + @ApiModelProperty(value = "角色, 0:Normal, 1:RD, 2:OP") + private Integer role; + + public AccountRoleVO(String username, Integer role) { + this.username = username; + this.role = role; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Integer getRole() { + return role; + } + + public void setRole(Integer role) { + this.role = role; + } + + @Override + public String toString() { + return "AccountRoleVO{" + + "username='" + username + '\'' + + ", role=" + role + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountSummaryVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountSummaryVO.java new file mode 100644 index 00000000..08ad1817 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountSummaryVO.java @@ -0,0 +1,53 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.common; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/8/26 + */ +@ApiModel(description = "账号概要信息") +public class AccountSummaryVO { + @ApiModelProperty(value = "账号") + private String username; + + @ApiModelProperty(value = "中文名") + private String chineseName; + + @ApiModelProperty(value = "部门") + private String department; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getChineseName() { + return chineseName; + } + + public void setChineseName(String chineseName) { + this.chineseName = chineseName; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + @Override + public String toString() { + return "AccountSummaryVO{" + + "username='" + username + '\'' + + ", chineseName='" + chineseName + '\'' + + ", department='" + department + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountVO.java new file mode 100644 index 00000000..33a2eba8 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/AccountVO.java @@ -0,0 +1,65 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.common; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/21 + */ +@ApiModel(description = "账号信息") +public class AccountVO { + @ApiModelProperty(value = "账号") + private String username; + + @ApiModelProperty(value = "中文名") + private String chineseName; + + @ApiModelProperty(value = "部门") + private String department; + + @ApiModelProperty(value = "角色, 0:Normal, 1:RD, 2:OP") + private Integer role; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getChineseName() { + return chineseName; + } + + public void setChineseName(String chineseName) { + this.chineseName = chineseName; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public Integer getRole() { + return role; + } + + public void setRole(Integer role) { + this.role = role; + } + + @Override + public String toString() { + return "AccountVO{" + + "username='" + username + '\'' + + ", chineseName='" + chineseName + '\'' + + ", department='" + department + '\'' + + ", role=" + role + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/BrokerOverviewVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/BrokerOverviewVO.java new file mode 100644 index 00000000..bf853853 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/BrokerOverviewVO.java @@ -0,0 +1,197 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.common; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 19/4/3 + */ +@ApiModel(description = "Broker信息概览") +public class BrokerOverviewVO { + @ApiModelProperty(value = "brokerId") + private Integer brokerId; + + @ApiModelProperty(value = "主机名") + private String host; + + @ApiModelProperty(value = "端口") + private Integer port; + + @ApiModelProperty(value = "jmx端口") + private Integer jmxPort; + + @ApiModelProperty(value = "启动时间") + private Long startTime; + + @ApiModelProperty(value = "流入流量") + private Object byteIn; + + @ApiModelProperty(value = "流出流量") + private Object byteOut; + + @ApiModelProperty(value = "分区数") + private Integer partitionCount; + + @ApiModelProperty(value = "已同步副本数") + private Integer underReplicatedPartitions; + + @ApiModelProperty(value = "未同步") + private Boolean underReplicated; + + @ApiModelProperty(value = "broker状态[0:在线, -1:不在线]") + private Integer status; + + @ApiModelProperty(value = "Region名称") + private String regionName; + + @ApiModelProperty(value = "峰值状态") + private Integer peakFlowStatus; + + @ApiModelProperty(value = "Kafka版本") + private String kafkaVersion; + + @ApiModelProperty(value = "Leader数") + private Integer leaderCount; + + public Integer getBrokerId() { + return brokerId; + } + + public void setBrokerId(Integer brokerId) { + this.brokerId = brokerId; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public Integer getJmxPort() { + return jmxPort; + } + + public void setJmxPort(Integer jmxPort) { + this.jmxPort = jmxPort; + } + + public Long getStartTime() { + return startTime; + } + + public void setStartTime(Long startTime) { + this.startTime = startTime; + } + + public Object getByteIn() { + return byteIn; + } + + public void setByteIn(Object byteIn) { + this.byteIn = byteIn; + } + + public Object getByteOut() { + return byteOut; + } + + public void setByteOut(Object byteOut) { + this.byteOut = byteOut; + } + + public Integer getPartitionCount() { + return partitionCount; + } + + public void setPartitionCount(Integer partitionCount) { + this.partitionCount = partitionCount; + } + + public Integer getUnderReplicatedPartitions() { + return underReplicatedPartitions; + } + + public void setUnderReplicatedPartitions(Integer underReplicatedPartitions) { + this.underReplicatedPartitions = underReplicatedPartitions; + } + + public Boolean getUnderReplicated() { + return underReplicated; + } + + public void setUnderReplicated(Boolean underReplicated) { + this.underReplicated = underReplicated; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getRegionName() { + return regionName; + } + + public void setRegionName(String regionName) { + this.regionName = regionName; + } + + public Integer getPeakFlowStatus() { + return peakFlowStatus; + } + + public void setPeakFlowStatus(Integer peakFlowStatus) { + this.peakFlowStatus = peakFlowStatus; + } + + public String getKafkaVersion() { + return kafkaVersion; + } + + public void setKafkaVersion(String kafkaVersion) { + this.kafkaVersion = kafkaVersion; + } + + public Integer getLeaderCount() { + return leaderCount; + } + + public void setLeaderCount(Integer leaderCount) { + this.leaderCount = leaderCount; + } + + @Override + public String toString() { + return "BrokerOverviewVO{" + + "brokerId=" + brokerId + + ", host='" + host + '\'' + + ", port=" + port + + ", jmxPort=" + jmxPort + + ", startTime=" + startTime + + ", byteIn=" + byteIn + + ", byteOut=" + byteOut + + ", partitionCount=" + partitionCount + + ", underReplicatedPartitions=" + underReplicatedPartitions + + ", underReplicated=" + underReplicated + + ", status=" + status + + ", regionName='" + regionName + '\'' + + ", peakFlowStatus=" + peakFlowStatus + + ", kafkaVersion='" + kafkaVersion + '\'' + + ", leaderCount=" + leaderCount + + '}'; + } +} diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/order/OrderPartitionVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/OrderPartitionVO.java similarity index 98% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/order/OrderPartitionVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/OrderPartitionVO.java index d39ca1e5..2e03f9a5 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/order/OrderPartitionVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/OrderPartitionVO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.order; +package com.xiaojukeji.kafka.manager.common.entity.vo.common; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/order/OrderTopicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/OrderTopicVO.java similarity index 98% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/order/OrderTopicVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/OrderTopicVO.java index 76817a9f..b5f95492 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/order/OrderTopicVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/OrderTopicVO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.order; +package com.xiaojukeji.kafka.manager.common.entity.vo.common; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicRealTimeMetricsVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/RealTimeMetricsVO.java similarity index 78% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicRealTimeMetricsVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/RealTimeMetricsVO.java index 1843fbe3..3dbd8272 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicRealTimeMetricsVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/RealTimeMetricsVO.java @@ -1,30 +1,39 @@ -package com.xiaojukeji.kafka.manager.web.vo.topic; +package com.xiaojukeji.kafka.manager.common.entity.vo.common; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import java.util.List; /** - * Topic实时流量信息 + * 实时流量信息 * @author zengqiao * @date 19/4/1 */ -@ApiModel(value = "Topic实时流量信息") -public class TopicRealTimeMetricsVO { +@ApiModel(value = "实时流量信息(Cluster/broker/Topic)") +public class RealTimeMetricsVO { + @ApiModelProperty(value = "每秒进入消息条") private List messageIn; + @ApiModelProperty(value = "每秒字节流入") private List byteIn; + @ApiModelProperty(value = "每秒字节流出") private List byteOut; + @ApiModelProperty(value = "每秒拒绝字节") private List byteRejected; + @ApiModelProperty(value = "失败fetch的请求") private List failedFetchRequest; + @ApiModelProperty(value = "失败produce的请求") private List failedProduceRequest; + @ApiModelProperty(value = "总的produce请求") private List totalProduceRequest; + @ApiModelProperty(value = "总的fetch请求") private List totalFetchRequest; public List getMessageIn() { @@ -93,7 +102,7 @@ public class TopicRealTimeMetricsVO { @Override public String toString() { - return "TopicRealTimeMetricsVO{" + + return "RealTimeMetricsVO{" + "messageIn=" + messageIn + ", byteIn=" + byteIn + ", byteOut=" + byteOut + diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicOverviewVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/TopicOverviewVO.java similarity index 54% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicOverviewVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/TopicOverviewVO.java index 1a5d6449..bf462ffc 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicOverviewVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/TopicOverviewVO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.topic; +package com.xiaojukeji.kafka.manager.common.entity.vo.common; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -8,14 +8,11 @@ import io.swagger.annotations.ApiModelProperty; * @author zengqiao * @date 19/4/1 */ -@ApiModel(value = "TopicOverviewVO", description = "Topic信息") +@ApiModel(description = "Topic信息概览") public class TopicOverviewVO { @ApiModelProperty(value = "集群ID") private Long clusterId; - @ApiModelProperty(value = "集群名称") - private String clusterName; - @ApiModelProperty(value = "Topic名称") private String topicName; @@ -25,20 +22,29 @@ public class TopicOverviewVO { @ApiModelProperty(value = "分区数") private Integer partitionNum; + @ApiModelProperty(value = "保存时间(ms)") + private Long retentionTime; + @ApiModelProperty(value = "每秒流入流量(B)") - private Double byteIn; + private Object byteIn; @ApiModelProperty(value = "发送请求数(个/秒)") - private Double produceRequest; + private Object produceRequest; + + @ApiModelProperty(value = "应用名称") + private String appName; + + @ApiModelProperty(value = "应用ID") + private String appId; + + @ApiModelProperty(value = "说明") + private String description; @ApiModelProperty(value = "Topic更新时间") private Long updateTime; - @ApiModelProperty(value = "负责人") - private String principals; - - @ApiModelProperty(value = "TRUE:已收藏的, FALSE:未收藏") - private Boolean favorite; + @ApiModelProperty(value = "逻辑集群id") + private Long logicalClusterId; public Long getClusterId() { return clusterId; @@ -48,14 +54,6 @@ public class TopicOverviewVO { this.clusterId = clusterId; } - public String getClusterName() { - return clusterName; - } - - public void setClusterName(String clusterName) { - this.clusterName = clusterName; - } - public String getTopicName() { return topicName; } @@ -80,22 +78,54 @@ public class TopicOverviewVO { this.partitionNum = partitionNum; } - public Double getByteIn() { + public Long getRetentionTime() { + return retentionTime; + } + + public void setRetentionTime(Long retentionTime) { + this.retentionTime = retentionTime; + } + + public Object getByteIn() { return byteIn; } - public void setByteIn(Double byteIn) { + public void setByteIn(Object byteIn) { this.byteIn = byteIn; } - public Double getProduceRequest() { + public Object getProduceRequest() { return produceRequest; } - public void setProduceRequest(Double produceRequest) { + public void setProduceRequest(Object produceRequest) { this.produceRequest = produceRequest; } + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + public Long getUpdateTime() { return updateTime; } @@ -104,35 +134,29 @@ public class TopicOverviewVO { this.updateTime = updateTime; } - public String getPrincipals() { - return principals; + public Long getLogicalClusterId() { + return logicalClusterId; } - public void setPrincipals(String principals) { - this.principals = principals; - } - - public Boolean getFavorite() { - return favorite; - } - - public void setFavorite(Boolean favorite) { - this.favorite = favorite; + public void setLogicalClusterId(Long logicalClusterId) { + this.logicalClusterId = logicalClusterId; } @Override public String toString() { return "TopicOverviewVO{" + "clusterId=" + clusterId + - ", clusterName='" + clusterName + '\'' + ", topicName='" + topicName + '\'' + ", replicaNum=" + replicaNum + ", partitionNum=" + partitionNum + + ", retentionTime=" + retentionTime + ", byteIn=" + byteIn + ", produceRequest=" + produceRequest + + ", appName='" + appName + '\'' + + ", appId='" + appId + '\'' + + ", description='" + description + '\'' + ", updateTime=" + updateTime + - ", principals='" + principals + '\'' + - ", favorite=" + favorite + + ", logicalClusterId=" + logicalClusterId + '}'; } } diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/TopicThrottleVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/TopicThrottleVO.java new file mode 100644 index 00000000..ca1c2d7a --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/common/TopicThrottleVO.java @@ -0,0 +1,67 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.common; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/4/28 + */ +@ApiModel(description="集群限流信息") +public class TopicThrottleVO { + @ApiModelProperty(value="Topic名称") + private String topicName; + + @ApiModelProperty(value="AppId") + private String appId; + + @ApiModelProperty(value="BrokerId列表") + private List brokerIdList; + + @ApiModelProperty(value = "客户端类型[Produce|Fetch]") + private String throttleClientType; + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public List getBrokerIdList() { + return brokerIdList; + } + + public void setBrokerIdList(List brokerIdList) { + this.brokerIdList = brokerIdList; + } + + public String getThrottleClientType() { + return throttleClientType; + } + + public void setThrottleClientType(String throttleClientType) { + this.throttleClientType = throttleClientType; + } + + @Override + public String toString() { + return "TopicThrottleVO{" + + "topicName='" + topicName + '\'' + + ", appId='" + appId + '\'' + + ", brokerIdList=" + brokerIdList + + ", throttleClientType='" + throttleClientType + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/GatewayConfigVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/GatewayConfigVO.java new file mode 100644 index 00000000..95707080 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/GatewayConfigVO.java @@ -0,0 +1,40 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.gateway; + +/** + * @author zengqiao + * @date 20/7/28 + */ +public class GatewayConfigVO { + private String version; + + private String data; + + public GatewayConfigVO(String version, String data) { + this.version = version; + this.data = data; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + @Override + public String toString() { + return "GatewayConfigVO{" + + "version='" + version + '\'' + + ", data='" + data + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaAclVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaAclVO.java new file mode 100644 index 00000000..5f0ac42c --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaAclVO.java @@ -0,0 +1,68 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.gateway; + +/** + * @author zengqiao + * @date 20/7/27 + */ +public class KafkaAclVO { + private String topicName; + + private Long timestamp; + + private Integer access; + + private Integer operation; + + private String username; + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + public Integer getAccess() { + return access; + } + + public void setAccess(Integer access) { + this.access = access; + } + + public Integer getOperation() { + return operation; + } + + public void setOperation(Integer operation) { + this.operation = operation; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + @Override + public String toString() { + return "KafkaAclVO{" + + "topicName='" + topicName + '\'' + + ", timestamp=" + timestamp + + ", access=" + access + + ", operation=" + operation + + ", username='" + username + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaSecurityVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaSecurityVO.java new file mode 100644 index 00000000..14192f35 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaSecurityVO.java @@ -0,0 +1,26 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.gateway; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/8/3 + */ +public class KafkaSecurityVO { + List rows; + + public List getRows() { + return rows; + } + + public void setRows(List rows) { + this.rows = rows; + } + + @Override + public String toString() { + return "KafkaSecurityVO{" + + "rows=" + rows + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaUserVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaUserVO.java new file mode 100644 index 00000000..bae66f85 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/gateway/KafkaUserVO.java @@ -0,0 +1,68 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.gateway; + +/** + * @author zengqiao + * @date 20/7/27 + */ +public class KafkaUserVO { + private String username; + + private String password; + + private Integer operation; + + private Long timestamp; + + private Integer userType; + + 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 Integer getOperation() { + return operation; + } + + public void setOperation(Integer operation) { + this.operation = operation; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + @Override + public String toString() { + return "KafkaUserVO{" + + "username='" + username + '\'' + + ", password='" + password + '\'' + + ", operation=" + operation + + ", timestamp=" + timestamp + + ", userType=" + userType + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillStaffDetailVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillStaffDetailVO.java new file mode 100644 index 00000000..9746aa3a --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillStaffDetailVO.java @@ -0,0 +1,55 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/4/26 + */ +@ApiModel(value = "用户月度账单详情") +public class BillStaffDetailVO { + @ApiModelProperty(value = "用户名") + private String username; + + @ApiModelProperty(value = "总金额") + private Double costSum; + + @ApiModelProperty(value = "账单详情") + private List billList; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Double getCostSum() { + return costSum; + } + + public void setCostSum(Double costSum) { + this.costSum = costSum; + } + + public List getBillList() { + return billList; + } + + public void setBillList(List billList) { + this.billList = billList; + } + + @Override + public String toString() { + return "BillStaffDetailVO{" + + "username='" + username + '\'' + + ", costSum=" + costSum + + ", billList=" + billList + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillStaffSummaryVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillStaffSummaryVO.java new file mode 100644 index 00000000..9e7d74e1 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillStaffSummaryVO.java @@ -0,0 +1,89 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/26 + */ +@ApiModel(value = "用户月度账单概览") +public class BillStaffSummaryVO { + @ApiModelProperty(value = "用户名") + private String username; + + @ApiModelProperty(value = "Topic数量") + private Integer topicNum; + + @ApiModelProperty(value = "配额") + private Double quota; + + @ApiModelProperty(value = "金额") + private Double cost; + + @ApiModelProperty(value = "月份") + private String gmtMonth; + + @ApiModelProperty(value = "时间戳") + private Long timestamp; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Integer getTopicNum() { + return topicNum; + } + + public void setTopicNum(Integer topicNum) { + this.topicNum = topicNum; + } + + public Double getQuota() { + return quota; + } + + public void setQuota(Double quota) { + this.quota = quota; + } + + public Double getCost() { + return cost; + } + + public void setCost(Double cost) { + this.cost = cost; + } + + public String getGmtMonth() { + return gmtMonth; + } + + public void setGmtMonth(String gmtMonth) { + this.gmtMonth = gmtMonth; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + @Override + public String toString() { + return "BillStaffSummaryVO{" + + "username='" + username + '\'' + + ", topicNum=" + topicNum + + ", quota=" + quota + + ", cost=" + cost + + ", gmtMonth='" + gmtMonth + '\'' + + ", timestamp=" + timestamp + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillTopicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillTopicVO.java new file mode 100644 index 00000000..33142c51 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/BillTopicVO.java @@ -0,0 +1,77 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/26 + */ +@ApiModel(value = "Topic账单") +public class BillTopicVO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "集群名称") + private String clusterName; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "配额") + private Double quota; + + @ApiModelProperty(value = "金额") + private Double cost; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Double getQuota() { + return quota; + } + + public void setQuota(Double quota) { + this.quota = quota; + } + + public Double getCost() { + return cost; + } + + public void setCost(Double cost) { + this.cost = cost; + } + + @Override + public String toString() { + return "BillTopicVO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", quota=" + quota + + ", cost=" + cost + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/QuotaVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/QuotaVO.java new file mode 100644 index 00000000..c741b677 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/QuotaVO.java @@ -0,0 +1,68 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal; + +/** + * @author zengqiao + * @date 20/5/12 + */ +public class QuotaVO { + private Long clusterId; + + private String topicName; + + private String appId; + + private Long produceQuota; + + private Long consumeQuota; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Long getProduceQuota() { + return produceQuota; + } + + public void setProduceQuota(Long produceQuota) { + this.produceQuota = produceQuota; + } + + public Long getConsumeQuota() { + return consumeQuota; + } + + public void setConsumeQuota(Long consumeQuota) { + this.consumeQuota = consumeQuota; + } + + @Override + public String toString() { + return "QuotaVO{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", appId='" + appId + '\'' + + ", produceQuota=" + produceQuota + + ", consumeQuota=" + consumeQuota + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/TopicBusinessInfoVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/TopicBusinessInfoVO.java new file mode 100644 index 00000000..61440a41 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/TopicBusinessInfoVO.java @@ -0,0 +1,77 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zhongyuankai + * @date 20/09/08 + */ +@ApiModel(value = "Topic业务信息") +public class TopicBusinessInfoVO { + @ApiModelProperty(value = "应用id") + private String appId; + + @ApiModelProperty(value = "应用名称") + private String appName; + + @ApiModelProperty(value = "负责人") + private String principals; + + @ApiModelProperty(value = "集群Id") + private Long clusterId; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getPrincipals() { + return principals; + } + + public void setPrincipals(String principals) { + this.principals = principals; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + @Override + public String toString() { + return "TopicBusinessInfoVO{" + + "appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", principals='" + principals + '\'' + + ", clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppSummaryVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppSummaryVO.java new file mode 100644 index 00000000..9cb486bf --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppSummaryVO.java @@ -0,0 +1,53 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.app; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/5/22 + */ +@ApiModel(description="App概览信息") +public class AppSummaryVO { + @ApiModelProperty(value="AppId") + private String appId; + + @ApiModelProperty(value="App名称") + private String name; + + @ApiModelProperty(value="App负责人") + private String principals; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPrincipals() { + return principals; + } + + public void setPrincipals(String principals) { + this.principals = principals; + } + + @Override + public String toString() { + return "AppSummaryVO{" + + "appId='" + appId + '\'' + + ", name='" + name + '\'' + + ", principals='" + principals + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppTopicAuthorityVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppTopicAuthorityVO.java new file mode 100644 index 00000000..d5a3fae4 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppTopicAuthorityVO.java @@ -0,0 +1,48 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.app; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +@ApiModel(value = "AppTopicAuthority") +public class AppTopicAuthorityVO { + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "appId") + private String appId; + + @ApiModelProperty(value = "权限: 0:无权限, 1:可消费 2:可发送 3:可发送消费 4:可管理") + private Integer access; + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Integer getAccess() { + return access; + } + + public void setAccess(Integer access) { + this.access = access; + } + + @Override + public String toString() { + return "AppTopicAuthorityVO{" + + ", topicName='" + topicName + '\'' + + ", appId='" + appId + '\'' + + ", access=" + access + + '}'; + } +} diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/MigrationTaskVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppTopicVO.java similarity index 56% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/MigrationTaskVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppTopicVO.java index 4a48fc15..228bcd85 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/MigrationTaskVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppTopicVO.java @@ -1,44 +1,31 @@ -package com.xiaojukeji.kafka.manager.web.vo; +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.app; +import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; /** - * 迁移任务 * @author zengqiao - * @date 19/7/13 + * @date 20/4/7 */ -public class MigrationTaskVO { - @ApiModelProperty(value = "任务ID") - private Long taskId; - - @ApiModelProperty(value = "集群ID") +@ApiModel(description="AppTopic") +public class AppTopicVO { + @ApiModelProperty(value = "逻辑集群ID") private Long clusterId; - @ApiModelProperty(value = "集群名称") + @ApiModelProperty(value = "逻辑集群名称") private String clusterName; @ApiModelProperty(value = "Topic名称") private String topicName; - @ApiModelProperty(value = "任务状态") - private Integer status; - - @ApiModelProperty(value = "限流值") - private Long throttle; - - @ApiModelProperty(value = "任务创建时间") - private Long gmtCreate; + @ApiModelProperty(value = "权限: 0:无权限, 1:可消费 2:可发送 3:可发送消费 4:可管理") + private Integer access; @ApiModelProperty(value = "操作人") private String operator; - public Long getTaskId() { - return taskId; - } - - public void setTaskId(Long taskId) { - this.taskId = taskId; - } + @ApiModelProperty(value = "权限授予时间") + private Long gmtCreate; public Long getClusterId() { return clusterId; @@ -64,28 +51,12 @@ public class MigrationTaskVO { this.topicName = topicName; } - public Integer getStatus() { - return status; + public Integer getAccess() { + return access; } - public void setStatus(Integer status) { - this.status = status; - } - - public Long getThrottle() { - return throttle; - } - - public void setThrottle(Long throttle) { - this.throttle = throttle; - } - - public Long getGmtCreate() { - return gmtCreate; - } - - public void setGmtCreate(Long gmtCreate) { - this.gmtCreate = gmtCreate; + public void setAccess(Integer access) { + this.access = access; } public String getOperator() { @@ -96,17 +67,23 @@ public class MigrationTaskVO { this.operator = operator; } + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } + @Override public String toString() { - return "MigrationTaskVO{" + - "taskId=" + taskId + - ", clusterId=" + clusterId + + return "AppTopicVO{" + + "clusterId=" + clusterId + ", clusterName='" + clusterName + '\'' + ", topicName='" + topicName + '\'' + - ", status=" + status + - ", throttle=" + throttle + - ", gmtCreate=" + gmtCreate + + ", access=" + access + ", operator='" + operator + '\'' + + ", gmtCreate=" + gmtCreate + '}'; } } \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppVO.java new file mode 100644 index 00000000..41ca8d92 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/AppVO.java @@ -0,0 +1,77 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.app; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/7 + */ +@ApiModel(description="App信息") +public class AppVO { + @ApiModelProperty(value="AppId") + private String appId; + + @ApiModelProperty(value="App名称") + private String name; + + @ApiModelProperty(value="App密码") + private String password; + + @ApiModelProperty(value="App描述") + private String description; + + @ApiModelProperty(value="App负责人") + private String principals; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getPrincipals() { + return principals; + } + + public void setPrincipals(String principals) { + this.principals = principals; + } + + @Override + public String toString() { + return "AppVO{" + + "appId='" + appId + '\'' + + ", name='" + name + '\'' + + ", password='" + password + '\'' + + ", description='" + description + '\'' + + ", principals='" + principals + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/DeprecatedAppVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/DeprecatedAppVO.java new file mode 100644 index 00000000..034cbc4f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/app/DeprecatedAppVO.java @@ -0,0 +1,214 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.app; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/8/13 + */ +@Deprecated +public class DeprecatedAppVO { + private Long id; + + private Date gmtCreate; + + private Date gmtModify; + + private String appId; + + private String name; + + private String password; + + private String type = "离线应用"; + + private String applicant; + + private String principal; + + private String department = ""; + + private Long department_id = null; + + private String description; + + private String approveUser = ""; + + private String approveTime = ""; + + private String approveInfo = ""; + + private Integer status = 1; + + private String bpmInstanceId = ""; + + private Boolean lastUsed = false; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getApplicant() { + return applicant; + } + + public void setApplicant(String applicant) { + this.applicant = applicant; + } + + public String getPrincipal() { + return principal; + } + + public void setPrincipal(String principal) { + this.principal = principal; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public Long getDepartment_id() { + return department_id; + } + + public void setDepartment_id(Long department_id) { + this.department_id = department_id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getApproveUser() { + return approveUser; + } + + public void setApproveUser(String approveUser) { + this.approveUser = approveUser; + } + + public String getApproveTime() { + return approveTime; + } + + public void setApproveTime(String approveTime) { + this.approveTime = approveTime; + } + + public String getApproveInfo() { + return approveInfo; + } + + public void setApproveInfo(String approveInfo) { + this.approveInfo = approveInfo; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getBpmInstanceId() { + return bpmInstanceId; + } + + public void setBpmInstanceId(String bpmInstanceId) { + this.bpmInstanceId = bpmInstanceId; + } + + public Boolean getLastUsed() { + return lastUsed; + } + + public void setLastUsed(Boolean lastUsed) { + this.lastUsed = lastUsed; + } + + @Override + public String toString() { + return "DeprecatedAppVO{" + + "id=" + id + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + ", appId='" + appId + '\'' + + ", name='" + name + '\'' + + ", password='" + password + '\'' + + ", type='" + type + '\'' + + ", applicant='" + applicant + '\'' + + ", principal='" + principal + '\'' + + ", department='" + department + '\'' + + ", department_id=" + department_id + + ", description='" + description + '\'' + + ", approveUser='" + approveUser + '\'' + + ", approveTime='" + approveTime + '\'' + + ", approveInfo='" + approveInfo + '\'' + + ", status=" + status + + ", bpmInstanceId='" + bpmInstanceId + '\'' + + ", lastUsed=" + lastUsed + + '}'; + } +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/cluster/ClusterBasicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/ClusterBasicVO.java similarity index 97% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/cluster/ClusterBasicVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/ClusterBasicVO.java index 185a4bf0..53410e05 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/cluster/ClusterBasicVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/ClusterBasicVO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.cluster; +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.cluster; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/ClusterNameDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/ClusterNameDTO.java new file mode 100644 index 00000000..e99005d5 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/ClusterNameDTO.java @@ -0,0 +1,70 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.cluster; + +import java.util.List; + +/** + * @author zhongyuankai + * @date 2020/5/18 + */ +public class ClusterNameDTO { + private Long physicalClusterId; + + private String physicalClusterName; + + private Long logicalClusterId; + + private String logicalClusterName; + + private List regionIdList; + + public Long getPhysicalClusterId() { + return physicalClusterId; + } + + public void setPhysicalClusterId(Long physicalClusterId) { + this.physicalClusterId = physicalClusterId; + } + + public String getPhysicalClusterName() { + return physicalClusterName; + } + + public void setPhysicalClusterName(String physicalClusterName) { + this.physicalClusterName = physicalClusterName; + } + + public Long getLogicalClusterId() { + return logicalClusterId; + } + + public void setLogicalClusterId(Long logicalClusterId) { + this.logicalClusterId = logicalClusterId; + } + + public String getLogicalClusterName() { + return logicalClusterName; + } + + public void setLogicalClusterName(String logicalClusterName) { + this.logicalClusterName = logicalClusterName; + } + + public List getRegionIdList() { + return regionIdList; + } + + public void setRegionIdList(List regionIdList) { + this.regionIdList = regionIdList; + } + + @Override + public String toString() { + return "ClusterNameDTO{" + + "physicalClusterId=" + physicalClusterId + + ", physicalClusterName='" + physicalClusterName + '\'' + + ", logicalClusterId=" + logicalClusterId + + ", logicalClusterName='" + logicalClusterName + '\'' + + ", regionIdList=" + regionIdList + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/LogicClusterVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/LogicClusterVO.java new file mode 100644 index 00000000..c3c5f9c3 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/LogicClusterVO.java @@ -0,0 +1,138 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.cluster; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/3/31 + */ +@ApiModel(description="逻辑集群信息") +public class LogicClusterVO { + @ApiModelProperty(value="逻辑集群ID") + private Long clusterId; + + @ApiModelProperty(value="逻辑集群名称") + private String clusterName; + + @ApiModelProperty(value="逻辑集群类型, 0:共享集群, 1:独享集群, 2:独立集群") + private Integer mode; + + @ApiModelProperty(value="逻辑Topic数量") + private Integer topicNum; + + @ApiModelProperty(value="集群版本") + private String clusterVersion; + + @ApiModelProperty(value="物理集群ID") + private Long physicalClusterId; + + @ApiModelProperty(value="集群服务地址") + private String bootstrapServers; + + @ApiModelProperty(value="描述") + private String description; + + @ApiModelProperty(value="接入时间") + private Long gmtCreate; + + @ApiModelProperty(value="修改时间") + private Long gmtModify; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public Integer getTopicNum() { + return topicNum; + } + + public void setTopicNum(Integer topicNum) { + this.topicNum = topicNum; + } + + public String getClusterVersion() { + return clusterVersion; + } + + public void setClusterVersion(String clusterVersion) { + this.clusterVersion = clusterVersion; + } + + public Long getPhysicalClusterId() { + return physicalClusterId; + } + + public void setPhysicalClusterId(Long physicalClusterId) { + this.physicalClusterId = physicalClusterId; + } + + public String getBootstrapServers() { + return bootstrapServers; + } + + public void setBootstrapServers(String bootstrapServers) { + this.bootstrapServers = bootstrapServers; + } + + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Long getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Long gmtModify) { + this.gmtModify = gmtModify; + } + + public Integer getMode() { + return mode; + } + + public void setMode(Integer mode) { + this.mode = mode; + } + + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "LogicClusterVO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", mode=" + mode + + ", topicNum=" + topicNum + + ", clusterVersion='" + clusterVersion + '\'' + + ", physicalClusterId=" + physicalClusterId + + ", bootstrapServers='" + bootstrapServers + '\'' + + ", description='" + description + '\'' + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + '}'; + } +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerMetricsVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/NormalClusterMetricsVO.java similarity index 61% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerMetricsVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/NormalClusterMetricsVO.java index 18d7e585..1d3c6601 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerMetricsVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/NormalClusterMetricsVO.java @@ -1,38 +1,31 @@ -package com.xiaojukeji.kafka.manager.web.vo.broker; +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.cluster; -import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; /** - * BROKER metrics * @author zengqiao - * @date 19/3/18 + * @date 20/5/13 */ -@ApiModel(value = "BrokerMetricsVO", description = "Broker流量信息") -public class BrokerMetricsVO { - @ApiModelProperty(value = "消息数") - private Double messagesInPerSec; +public class NormalClusterMetricsVO { - @ApiModelProperty(value = "流入流量(B)") + @ApiModelProperty(value="每秒总共发送的请求") + private Double totalProduceRequestsPerSec; + + @ApiModelProperty(value="每秒流入的字节数") private Double bytesInPerSec; - @ApiModelProperty(value = "流出流量(B)") + @ApiModelProperty(value="每秒流出的字节数") private Double bytesOutPerSec; - @ApiModelProperty(value = "被拒绝流量(B)") + @ApiModelProperty(value="每秒拒绝的字节数") private Double bytesRejectedPerSec; - @ApiModelProperty(value = "创建时间") + @ApiModelProperty(value="每秒流入的消息数") + private Double messagesInPerSec; + + @ApiModelProperty(value="创建时间") private Long gmtCreate; - public Double getMessagesInPerSec() { - return messagesInPerSec; - } - - public void setMessagesInPerSec(Double messagesInPerSec) { - this.messagesInPerSec = messagesInPerSec; - } - public Double getBytesInPerSec() { return bytesInPerSec; } @@ -57,6 +50,14 @@ public class BrokerMetricsVO { this.bytesRejectedPerSec = bytesRejectedPerSec; } + public Double getMessagesInPerSec() { + return messagesInPerSec; + } + + public void setMessagesInPerSec(Double messagesInPerSec) { + this.messagesInPerSec = messagesInPerSec; + } + public Long getGmtCreate() { return gmtCreate; } @@ -65,14 +66,23 @@ public class BrokerMetricsVO { this.gmtCreate = gmtCreate; } + public Double getTotalProduceRequestsPerSec() { + return totalProduceRequestsPerSec; + } + + public void setTotalProduceRequestsPerSec(Double totalProduceRequestsPerSec) { + this.totalProduceRequestsPerSec = totalProduceRequestsPerSec; + } + @Override public String toString() { - return "BrokerMetricsVO{" + - "messagesInPerSec=" + messagesInPerSec + + return "NormalClusterMetricsVO{" + + "totalProduceRequestsPerSec=" + totalProduceRequestsPerSec + ", bytesInPerSec=" + bytesInPerSec + ", bytesOutPerSec=" + bytesOutPerSec + ", bytesRejectedPerSec=" + bytesRejectedPerSec + + ", messagesInPerSec=" + messagesInPerSec + ", gmtCreate=" + gmtCreate + '}'; } -} +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/TopicMetadataVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/TopicMetadataVO.java new file mode 100644 index 00000000..26965ae3 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/cluster/TopicMetadataVO.java @@ -0,0 +1,55 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.cluster; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/4/29 + */ +@ApiModel(description="Topic元信息") +public class TopicMetadataVO { + @ApiModelProperty(value="Topic名称") + private String topicName; + + @ApiModelProperty(value="Topic分区列表") + private List partitionIdList; + + @ApiModelProperty(value="Topic分区数") + private Integer partitionNum; + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public List getPartitionIdList() { + return partitionIdList; + } + + public void setPartitionIdList(List partitionIdList) { + this.partitionIdList = partitionIdList; + } + + public Integer getPartitionNum() { + return partitionNum; + } + + public void setPartitionNum(Integer partitionNum) { + this.partitionNum = partitionNum; + } + + @Override + public String toString() { + return "TopicMetadataVO{" + + "topicName='" + topicName + '\'' + + ", partitionIdList=" + partitionIdList + + ", partitionNum=" + partitionNum + + '}'; + } +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/consumer/ConsumerGroupDetailVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/consumer/ConsumerGroupDetailVO.java similarity index 77% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/consumer/ConsumerGroupDetailVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/consumer/ConsumerGroupDetailVO.java index 054e98e0..d70557e2 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/consumer/ConsumerGroupDetailVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/consumer/ConsumerGroupDetailVO.java @@ -1,36 +1,38 @@ -package com.xiaojukeji.kafka.manager.web.vo.consumer; +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.consumer; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; /** * @author zengqiao * @date 19/4/3 */ +@ApiModel(value = "消费组的消费详情") public class ConsumerGroupDetailVO { - private Long clusterId; - + @ApiModelProperty(value = "topic名称") private String topicName; + @ApiModelProperty(value = "消费组名称") private String consumerGroup; + @ApiModelProperty(value = "location") private String location; + @ApiModelProperty(value = "分区Id") private Integer partitionId; + @ApiModelProperty(value = "clientId") private String clientId; + @ApiModelProperty(value = "消费偏移量") private Long consumeOffset; + @ApiModelProperty(value = "partitionOffset") private Long partitionOffset; + @ApiModelProperty(value = "lag") private Long lag; - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - public String getTopicName() { return topicName; } @@ -98,8 +100,7 @@ public class ConsumerGroupDetailVO { @Override public String toString() { return "ConsumerGroupDetailVO{" + - "clusterId=" + clusterId + - ", topicName='" + topicName + '\'' + + "topicName='" + topicName + '\'' + ", consumerGroup='" + consumerGroup + '\'' + ", location='" + location + '\'' + ", partitionId=" + partitionId + diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/consumer/ConsumerGroupVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/consumer/ConsumerGroupVO.java similarity index 56% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/consumer/ConsumerGroupVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/consumer/ConsumerGroupVO.java index de654ccd..9c09eb6f 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/consumer/ConsumerGroupVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/consumer/ConsumerGroupVO.java @@ -1,27 +1,23 @@ -package com.xiaojukeji.kafka.manager.web.vo.consumer; +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.consumer; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import java.io.Serializable; /** - * 消费组信息 - * @author zengqiao - * @date 19/4/3 + * @author zhongyuankai + * @date 20/4/8 */ -@ApiModel(value = "ConsumerGroupVO", description = "消费组信息") -public class ConsumerGroupVO implements Serializable { +@ApiModel(value = "消费组消费Topic信息") +public class ConsumerGroupVO { @ApiModelProperty(value = "消费组名称") private String consumerGroup; - @ApiModelProperty(value = "存储位置") - private String location; + @ApiModelProperty(value = "使用的AppID") + private String appIds; - public ConsumerGroupVO(String consumerGroup, String location) { - this.consumerGroup = consumerGroup; - this.location = location; - } + @ApiModelProperty(value = "offset存储位置") + private String location; public String getConsumerGroup() { return consumerGroup; @@ -31,6 +27,14 @@ public class ConsumerGroupVO implements Serializable { this.consumerGroup = consumerGroup; } + public String getAppIds() { + return appIds; + } + + public void setAppIds(String appIds) { + this.appIds = appIds; + } + public String getLocation() { return location; } @@ -42,7 +46,8 @@ public class ConsumerGroupVO implements Serializable { @Override public String toString() { return "ConsumerGroupVO{" + - "consumerGroup='" + consumerGroup + '\'' + + ", consumerGroup='" + consumerGroup + '\'' + + ", appIds='" + appIds + '\'' + ", location='" + location + '\'' + '}'; } diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderResultVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderResultVO.java new file mode 100644 index 00000000..67686acd --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderResultVO.java @@ -0,0 +1,38 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.order; + +import com.xiaojukeji.kafka.manager.common.entity.Result; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "工单审批结果") +public class OrderResultVO { + @ApiModelProperty(value = "工单ID") + private Long id; + + @ApiModelProperty(value = "审批结果") + private Result result; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Result getResult() { + return result; + } + + public void setResult(Result result) { + this.result = result; + } + + @Override + public String toString() { + return "OrderResultVO{" + + "id=" + id + + ", result=" + result + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderTypeVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderTypeVO.java new file mode 100644 index 00000000..e75f8e8b --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderTypeVO.java @@ -0,0 +1,47 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.order; + +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zhongyuankai + * @date 20/4/24 + */ +public class OrderTypeVO { + @ApiModelProperty(value = "工单类型") + private Integer type; + + @ApiModelProperty(value = "描述信息") + private String message; + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public OrderTypeVO(Integer type, String message) { + this.type = type; + this.message = message; + } + + public OrderTypeVO() { + } + + @Override + public String toString() { + return "OrderTypeVO{" + + "type=" + type + + ", message='" + message + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderVO.java new file mode 100644 index 00000000..390d3ef4 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/OrderVO.java @@ -0,0 +1,101 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.order; + +import io.swagger.annotations.ApiModelProperty; + +import java.util.Date; + +/** + * @author zhongyuankai + * @date 20/4/21 + */ +public class OrderVO { + @ApiModelProperty(value = "工单ID") + private Long id; + + @ApiModelProperty(value = "工单类型, 0:topics, 1:apps, 2:quotas, 3:authorities, 4:clusters") + private Integer type; + + @ApiModelProperty(value = "工单标题") + private String title; + + @ApiModelProperty(value = "申请人") + private String applicant; + + @ApiModelProperty(value = "描述信息") + private String description; + + @ApiModelProperty(value = "工单状态, 0:待审批, 1:通过, 2:拒绝, 3:取消") + private Integer status; + + @ApiModelProperty(value = "申请/审核时间") + private Date gmtTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getGmtTime() { + return gmtTime; + } + + public void setGmtTime(Date gmtTime) { + this.gmtTime = gmtTime; + } + + public String getApplicant() { + return applicant; + } + + public void setApplicant(String applicant) { + this.applicant = applicant; + } + + @Override + public String toString() { + return "OrderVO{" + + "id=" + id + + ", type=" + type + + ", title='" + title + '\'' + + ", applicant='" + applicant + '\'' + + ", description='" + description + '\'' + + ", status=" + status + + ", gmtTime=" + gmtTime + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/detail/OrderDetailBaseVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/detail/OrderDetailBaseVO.java new file mode 100644 index 00000000..9d5e5623 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/order/detail/OrderDetailBaseVO.java @@ -0,0 +1,153 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.order.detail; + +import com.xiaojukeji.kafka.manager.common.entity.vo.common.AccountVO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.Date; +import java.util.List; + +/** + * @author zengqiao + * @date 20/4/21 + */ +@ApiModel(description = "工单详情类") +public class OrderDetailBaseVO { + @ApiModelProperty(value = "工单ID") + private Long id; + + @ApiModelProperty(value = "工单类型") + private Integer type; + + @ApiModelProperty(value = "工单标题") + private String title; + + @ApiModelProperty(value = "申请人") + private AccountVO applicant; + + @ApiModelProperty(value = "申请时间") + private Date gmtCreate; + + @ApiModelProperty(value = "审批人列表, 状态为未处理时返回的是审批人, 状态为处理完成时返回的是审批的人") + private List approverList; + + @ApiModelProperty(value = "审批时间") + private Date gmtHandle; + + @ApiModelProperty(value = "审批审批意见") + private String opinion; + + @ApiModelProperty(value = "工单状态, 0:待审批, 1:通过, 2:拒绝, 3:取消") + private Integer status; + + @ApiModelProperty(value = "备注") + private String description; + + @ApiModelProperty(value = "工单明细") + private T detail; + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public AccountVO getApplicant() { + return applicant; + } + + public void setApplicant(AccountVO applicant) { + this.applicant = applicant; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public List getApproverList() { + return approverList; + } + + public void setApproverList(List approverList) { + this.approverList = approverList; + } + + public Date getGmtHandle() { + return gmtHandle; + } + + public void setGmtHandle(Date gmtHandle) { + this.gmtHandle = gmtHandle; + } + + public String getOpinion() { + return opinion; + } + + public void setOpinion(String opinion) { + this.opinion = opinion; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public T getDetail() { + return detail; + } + + public void setDetail(T detail) { + this.detail = detail; + } + + @Override + public String toString() { + return "OrderDetailBaseVO{" + + "id=" + id + + ", type=" + type + + ", title='" + title + '\'' + + ", applicant=" + applicant + + ", gmtCreate=" + gmtCreate + + ", approverList=" + approverList + + ", gmtHandle=" + gmtHandle + + ", opinion='" + opinion + '\'' + + ", status=" + status + + ", description='" + description + '\'' + + ", detail=" + detail + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicAuthorizedAppVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicAuthorizedAppVO.java new file mode 100644 index 00000000..4979e338 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicAuthorizedAppVO.java @@ -0,0 +1,125 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zhongyuankai + * @date 20/4/8 + */ +@ApiModel(value = "TopicApp信息") +public class TopicAuthorizedAppVO { + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "应用id") + private String appId; + + @ApiModelProperty(value = "应用名称") + private String appName; + + @ApiModelProperty(value = "负责人") + private String appPrincipals; + + @ApiModelProperty(value = "发送Quota(B/s)") + private Long produceQuota; + + @ApiModelProperty(value = "消费Quota(B/s)") + private Long consumerQuota; + + @ApiModelProperty(value = "生产被限流") + private Boolean produceThrottled; + + @ApiModelProperty(value = "消费被限流") + private Boolean fetchThrottled; + + @ApiModelProperty(value = "权限, 0:无权限, 1:可消费, 2:可发送, 3:可消费发送, 4:可管理") + private Integer access; + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppPrincipals() { + return appPrincipals; + } + + public void setAppPrincipals(String appPrincipals) { + this.appPrincipals = appPrincipals; + } + + public Long getProduceQuota() { + return produceQuota; + } + + public void setProduceQuota(Long produceQuota) { + this.produceQuota = produceQuota; + } + + public Long getConsumerQuota() { + return consumerQuota; + } + + public void setConsumerQuota(Long consumerQuota) { + this.consumerQuota = consumerQuota; + } + + public Boolean getProduceThrottled() { + return produceThrottled; + } + + public void setProduceThrottled(Boolean produceThrottled) { + this.produceThrottled = produceThrottled; + } + + public Boolean getFetchThrottled() { + return fetchThrottled; + } + + public void setFetchThrottled(Boolean fetchThrottled) { + this.fetchThrottled = fetchThrottled; + } + + public Integer getAccess() { + return access; + } + + public void setAccess(Integer access) { + this.access = access; + } + + @Override + public String toString() { + return "TopicAppVO{" + + "topicName='" + topicName + '\'' + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", appPrincipals='" + appPrincipals + '\'' + + ", produceQuota=" + produceQuota + + ", consumerQuota=" + consumerQuota + + ", produceThrottled=" + produceThrottled + + ", fetchThrottled=" + fetchThrottled + + ", access=" + access + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicBasicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicBasicVO.java new file mode 100644 index 00000000..f3fcb952 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicBasicVO.java @@ -0,0 +1,174 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * Topic的基本信息 + * @author zengqiao + * @date 19/4/1 + */ +@ApiModel(description = "Topic基本信息") +public class TopicBasicVO { + @ApiModelProperty(value = "集群id") + private Long clusterId; + + @ApiModelProperty(value = "应用id") + private String appId; + + @ApiModelProperty(value = "应用名称") + private String appName; + + @ApiModelProperty(value = "分区数") + private Integer partitionNum; + + @ApiModelProperty(value = "副本数") + private Integer replicaNum; + + @ApiModelProperty(value = "负责人") + private String principals; + + @ApiModelProperty(value = "存储时间(ms)") + private Long retentionTime; + + @ApiModelProperty(value = "创建时间") + private Long createTime; + + @ApiModelProperty(value = "修改时间") + private Long modifyTime; + + @ApiModelProperty(value = "健康分") + private Integer score; + + @ApiModelProperty(value = "压缩格式") + private String topicCodeC; + + @ApiModelProperty(value = "备注") + private String description; + + @ApiModelProperty(value = "集群地址") + private String bootstrapServers; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicCodeC() { + return topicCodeC; + } + + public void setTopicCodeC(String topicCodeC) { + this.topicCodeC = topicCodeC; + } + + public Integer getPartitionNum() { + return partitionNum; + } + + public void setPartitionNum(Integer partitionNum) { + this.partitionNum = partitionNum; + } + + public Integer getReplicaNum() { + return replicaNum; + } + + public void setReplicaNum(Integer replicaNum) { + this.replicaNum = replicaNum; + } + + public Long getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Long modifyTime) { + this.modifyTime = modifyTime; + } + + public Long getCreateTime() { + return createTime; + } + + public void setCreateTime(Long createTime) { + this.createTime = createTime; + } + + public String getPrincipals() { + return principals; + } + + public void setPrincipals(String principals) { + this.principals = principals; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public void setBootstrapServers(String bootstrapServers) { + this.bootstrapServers = bootstrapServers; + } + + public String getAppId() { + return appId; + } + + public String getBootstrapServers() { + return bootstrapServers; + } + + public Long getRetentionTime() { + return retentionTime; + } + + public void setRetentionTime(Long retentionTime) { + this.retentionTime = retentionTime; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public Integer getScore() { + return score; + } + + public void setScore(Integer score) { + this.score = score; + } + + @Override + public String toString() { + return "TopicBasicVO{" + + "clusterId=" + clusterId + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", partitionNum=" + partitionNum + + ", replicaNum=" + replicaNum + + ", principals='" + principals + '\'' + + ", retentionTime=" + retentionTime + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + ", score=" + score + + ", topicCodeC='" + topicCodeC + '\'' + + ", description='" + description + '\'' + + ", bootstrapServers='" + bootstrapServers + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicBillVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicBillVO.java new file mode 100644 index 00000000..64e62adb --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicBillVO.java @@ -0,0 +1,53 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/5/11 + */ +@ApiModel(value = "Topic账单") +public class TopicBillVO { + @ApiModelProperty(value = "配额") + private Long quota; + + @ApiModelProperty(value = "金额") + private Double cost; + + @ApiModelProperty(value = "月份") + private String gmtMonth; + + public Long getQuota() { + return quota; + } + + public void setQuota(Long quota) { + this.quota = quota; + } + + public Double getCost() { + return cost; + } + + public void setCost(Double cost) { + this.cost = cost; + } + + public String getGmtMonth() { + return gmtMonth; + } + + public void setGmtMonth(String gmtMonth) { + this.gmtMonth = gmtMonth; + } + + @Override + public String toString() { + return "TopicBillVO{" + + "quota=" + quota + + ", cost=" + cost + + ", gmtMonth='" + gmtMonth + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicConnectionVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicConnectionVO.java new file mode 100644 index 00000000..e6d65b91 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicConnectionVO.java @@ -0,0 +1,101 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zhongyuankai,zengqiao + * @date 20/4/8 + */ +@ApiModel(value = "Topic连接信息") +public class TopicConnectionVO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "topic名称") + private String topicName; + + @ApiModelProperty(value = "AppID") + private String appId; + + @ApiModelProperty(value = "ip") + private String ip; + + @ApiModelProperty(value = "主机名") + private String hostname; + + @ApiModelProperty(value = "客户端类型[consume|produce]") + private String clientType; + + @ApiModelProperty(value = "客户端版本") + private String clientVersion; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public String getClientType() { + return clientType; + } + + public void setClientType(String clientType) { + this.clientType = clientType; + } + + public String getClientVersion() { + return clientVersion; + } + + public void setClientVersion(String clientVersion) { + this.clientVersion = clientVersion; + } + + @Override + public String toString() { + return "TopicConnectionVO{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", appId='" + appId + '\'' + + ", ip='" + ip + '\'' + + ", hostname='" + hostname + '\'' + + ", clientType='" + clientType + '\'' + + ", clientVersion='" + clientVersion + '\'' + + '}'; + } +} diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicDataSampleVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicDataSampleVO.java similarity index 89% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicDataSampleVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicDataSampleVO.java index b7f29643..d4d941f8 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicDataSampleVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicDataSampleVO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.topic; +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicDeleteVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicDeleteVO.java similarity index 96% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicDeleteVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicDeleteVO.java index 9717b8f4..5f7069ba 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicDeleteVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicDeleteVO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.topic; +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicDetailVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicDetailVO.java similarity index 97% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicDetailVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicDetailVO.java index 308f304f..3708eaf5 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicDetailVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicDetailVO.java @@ -1,8 +1,7 @@ -package com.xiaojukeji.kafka.manager.web.vo.topic; +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; import io.swagger.annotations.ApiModel; -import java.util.Date; import java.util.List; /** diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicExpiredVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicExpiredVO.java new file mode 100644 index 00000000..79fdcfd3 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicExpiredVO.java @@ -0,0 +1,101 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/3/31 + */ +@ApiModel(value = "过期Topic") +public class TopicExpiredVO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "集群名称") + private String clusterName; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "AppID") + private String appId; + + @ApiModelProperty(value = "App名称") + private String appName; + + @ApiModelProperty(value = "App负责人") + private String appPrincipals; + + @ApiModelProperty(value = "消费连接个数") + private Integer fetchConnectionNum; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppPrincipals() { + return appPrincipals; + } + + public void setAppPrincipals(String appPrincipals) { + this.appPrincipals = appPrincipals; + } + + public Integer getFetchConnectionNum() { + return fetchConnectionNum; + } + + public void setFetchConnectionNum(Integer fetchConnectionNum) { + this.fetchConnectionNum = fetchConnectionNum; + } + + @Override + public String toString() { + return "TopicExpiredVO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", appPrincipals='" + appPrincipals + '\'' + + ", fetchConnectionNum=" + fetchConnectionNum + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMetricVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMetricVO.java new file mode 100644 index 00000000..1e5b6a46 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMetricVO.java @@ -0,0 +1,149 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author huangyiminghappy@163.com + * @date 20/4/2 + */ +@ApiModel(value = "Topic流量信息") +public class TopicMetricVO { + @ApiModelProperty(value = "每秒流入消息数") + private Object messagesInPerSec; + + @ApiModelProperty(value = "每秒流入字节数") + private Object bytesInPerSec; + + @ApiModelProperty(value = "每秒流出字节数") + private Object bytesOutPerSec; + + @ApiModelProperty(value = "每秒拒绝字节数") + private Object bytesRejectedPerSec; + + @ApiModelProperty(value = "每秒请求数") + private Object totalProduceRequestsPerSec; + + @ApiModelProperty(value = "appId维度每秒流入消息数") + private Object appIdMessagesInPerSec; + + @ApiModelProperty(value = "appId维度每秒流入字节数") + private Object appIdBytesInPerSec; + + @ApiModelProperty(value = "appId维度每秒流出字节数") + private Object appIdBytesOutPerSec; + + @ApiModelProperty(value = "produce限流") + private Boolean produceThrottled; + + @ApiModelProperty(value = "consume限流") + private Boolean consumeThrottled; + + @ApiModelProperty(value = "创建时间") + private Long gmtCreate; + + public Object getMessagesInPerSec() { + return messagesInPerSec; + } + + public void setMessagesInPerSec(Object messagesInPerSec) { + this.messagesInPerSec = messagesInPerSec; + } + + public Object getBytesInPerSec() { + return bytesInPerSec; + } + + public void setBytesInPerSec(Object bytesInPerSec) { + this.bytesInPerSec = bytesInPerSec; + } + + public Object getBytesOutPerSec() { + return bytesOutPerSec; + } + + public void setBytesOutPerSec(Object bytesOutPerSec) { + this.bytesOutPerSec = bytesOutPerSec; + } + + public Object getBytesRejectedPerSec() { + return bytesRejectedPerSec; + } + + public void setBytesRejectedPerSec(Object bytesRejectedPerSec) { + this.bytesRejectedPerSec = bytesRejectedPerSec; + } + + public Object getTotalProduceRequestsPerSec() { + return totalProduceRequestsPerSec; + } + + public void setTotalProduceRequestsPerSec(Object totalProduceRequestsPerSec) { + this.totalProduceRequestsPerSec = totalProduceRequestsPerSec; + } + + public Object getAppIdMessagesInPerSec() { + return appIdMessagesInPerSec; + } + + public void setAppIdMessagesInPerSec(Object appIdMessagesInPerSec) { + this.appIdMessagesInPerSec = appIdMessagesInPerSec; + } + + public Object getAppIdBytesInPerSec() { + return appIdBytesInPerSec; + } + + public void setAppIdBytesInPerSec(Object appIdBytesInPerSec) { + this.appIdBytesInPerSec = appIdBytesInPerSec; + } + + public Object getAppIdBytesOutPerSec() { + return appIdBytesOutPerSec; + } + + public void setAppIdBytesOutPerSec(Object appIdBytesOutPerSec) { + this.appIdBytesOutPerSec = appIdBytesOutPerSec; + } + + public Boolean getProduceThrottled() { + return produceThrottled; + } + + public void setProduceThrottled(Boolean produceThrottled) { + this.produceThrottled = produceThrottled; + } + + public Boolean getConsumeThrottled() { + return consumeThrottled; + } + + public void setConsumeThrottled(Boolean consumeThrottled) { + this.consumeThrottled = consumeThrottled; + } + + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } + + @Override + public String toString() { + return "TopicMetricVO{" + + "messagesInPerSec=" + messagesInPerSec + + ", bytesInPerSec=" + bytesInPerSec + + ", bytesOutPerSec=" + bytesOutPerSec + + ", bytesRejectedPerSec=" + bytesRejectedPerSec + + ", totalProduceRequestsPerSec=" + totalProduceRequestsPerSec + + ", appIdMessagesInPerSec=" + appIdMessagesInPerSec + + ", appIdBytesInPerSec=" + appIdBytesInPerSec + + ", appIdBytesOutPerSec=" + appIdBytesOutPerSec + + ", produceThrottled=" + produceThrottled + + ", consumeThrottled=" + consumeThrottled + + ", gmtCreate=" + gmtCreate + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMineVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMineVO.java new file mode 100644 index 00000000..2cda46cb --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMineVO.java @@ -0,0 +1,125 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/3/31 + */ +@ApiModel(description = "Topic信息") +public class TopicMineVO { + @ApiModelProperty(value = "逻辑集群ID") + private Long clusterId; + + @ApiModelProperty(value = "逻辑集群名称") + private String clusterName; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "流入流量(B/s)") + private Object bytesIn; + + @ApiModelProperty(value = "流出流量(B/s)") + private Object bytesOut; + + @ApiModelProperty(value = "AppID") + private String appId; + + @ApiModelProperty(value = "App名称") + private String appName; + + @ApiModelProperty(value = "App负责人") + private String appPrincipals; + + @ApiModelProperty(value = "状态, 0:无权限, 1:可消费 2:可发送 3:可消费发送 4:可管理") + private Integer access; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Object getBytesIn() { + return bytesIn; + } + + public void setBytesIn(Object bytesIn) { + this.bytesIn = bytesIn; + } + + public Object getBytesOut() { + return bytesOut; + } + + public void setBytesOut(Object bytesOut) { + this.bytesOut = bytesOut; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppPrincipals() { + return appPrincipals; + } + + public void setAppPrincipals(String appPrincipals) { + this.appPrincipals = appPrincipals; + } + + public Integer getAccess() { + return access; + } + + public void setAccess(Integer access) { + this.access = access; + } + + @Override + public String toString() { + return "TopicMineVO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", bytesIn=" + bytesIn + + ", bytesOut=" + bytesOut + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", appPrincipals='" + appPrincipals + '\'' + + ", access=" + access + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMyAppVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMyAppVO.java new file mode 100644 index 00000000..c89ba73d --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicMyAppVO.java @@ -0,0 +1,89 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/9/16 + */ +@ApiModel(value = "我的应用对Topic的信息") +public class TopicMyAppVO { + @ApiModelProperty(value = "应用id") + private String appId; + + @ApiModelProperty(value = "应用名称") + private String appName; + + @ApiModelProperty(value = "负责人") + private String appPrincipals; + + @ApiModelProperty(value = "发送Quota(B/s)") + private Long produceQuota; + + @ApiModelProperty(value = "消费Quota(B/s)") + private Long consumerQuota; + + @ApiModelProperty(value = "权限, 0:无权限, 1:可消费, 2:可发送, 3:可消费发送") + private Integer access; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppPrincipals() { + return appPrincipals; + } + + public void setAppPrincipals(String appPrincipals) { + this.appPrincipals = appPrincipals; + } + + public Long getProduceQuota() { + return produceQuota; + } + + public void setProduceQuota(Long produceQuota) { + this.produceQuota = produceQuota; + } + + public Long getConsumerQuota() { + return consumerQuota; + } + + public void setConsumerQuota(Long consumerQuota) { + this.consumerQuota = consumerQuota; + } + + public Integer getAccess() { + return access; + } + + public void setAccess(Integer access) { + this.access = access; + } + + @Override + public String toString() { + return "TopicMyAppVO{" + + "appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", appPrincipals='" + appPrincipals + '\'' + + ", produceQuota=" + produceQuota + + ", consumerQuota=" + consumerQuota + + ", access=" + access + + '}'; + } +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicOffsetVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicOffsetVO.java similarity index 96% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicOffsetVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicOffsetVO.java index d3270ac6..9313ef30 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicOffsetVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicOffsetVO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.topic; +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicPartitionVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicPartitionVO.java new file mode 100644 index 00000000..a66771e5 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicPartitionVO.java @@ -0,0 +1,139 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author arthur + * @date 2017/6/6. + */ +@ApiModel(value = "分区信息") +public class TopicPartitionVO { + @ApiModelProperty(value = "分区ID") + private Integer partitionId; + + @ApiModelProperty(value = "起始偏移") + private Long beginningOffset; + + @ApiModelProperty(value = "结尾偏移") + private Long endOffset; + + @ApiModelProperty(value = "消息条数") + private Long msgNum; + + @ApiModelProperty(value = "Leader副本") + private Integer leaderBrokerId; + + @ApiModelProperty(value = "首选副本") + private Integer preferredBrokerId; + + @ApiModelProperty(value = "replicas") + private List replicaBrokerIdList; + + @ApiModelProperty(value = "ISR") + private List isrBrokerIdList; + + @ApiModelProperty(value = "True:未同步, False:已同步") + private Boolean underReplicated; + + @ApiModelProperty(value = "Leader副本的大小(B)") + private Long logSize; + + public Integer getPartitionId() { + return partitionId; + } + + public void setPartitionId(Integer partitionId) { + this.partitionId = partitionId; + } + + public Long getBeginningOffset() { + return beginningOffset; + } + + public void setBeginningOffset(Long beginningOffset) { + this.beginningOffset = beginningOffset; + } + + public Long getEndOffset() { + return endOffset; + } + + public void setEndOffset(Long endOffset) { + this.endOffset = endOffset; + } + + public Long getMsgNum() { + return msgNum; + } + + public void setMsgNum(Long msgNum) { + this.msgNum = msgNum; + } + + public Integer getLeaderBrokerId() { + return leaderBrokerId; + } + + public void setLeaderBrokerId(Integer leaderBrokerId) { + this.leaderBrokerId = leaderBrokerId; + } + + public Integer getPreferredBrokerId() { + return preferredBrokerId; + } + + public void setPreferredBrokerId(Integer preferredBrokerId) { + this.preferredBrokerId = preferredBrokerId; + } + + public List getReplicaBrokerIdList() { + return replicaBrokerIdList; + } + + public void setReplicaBrokerIdList(List replicaBrokerIdList) { + this.replicaBrokerIdList = replicaBrokerIdList; + } + + public List getIsrBrokerIdList() { + return isrBrokerIdList; + } + + public void setIsrBrokerIdList(List isrBrokerIdList) { + this.isrBrokerIdList = isrBrokerIdList; + } + + public Boolean getUnderReplicated() { + return underReplicated; + } + + public void setUnderReplicated(Boolean underReplicated) { + this.underReplicated = underReplicated; + } + + public Long getLogSize() { + return logSize; + } + + public void setLogSize(Long logSize) { + this.logSize = logSize; + } + + @Override + public String toString() { + return "TopicPartitionVO{" + + "partitionId=" + partitionId + + ", beginningOffset=" + beginningOffset + + ", endOffset=" + endOffset + + ", msgNum=" + msgNum + + ", leaderBrokerId=" + leaderBrokerId + + ", preferredBrokerId=" + preferredBrokerId + + ", replicaBrokerIdList=" + replicaBrokerIdList + + ", isrBrokerIdList=" + isrBrokerIdList + + ", underReplicated=" + underReplicated + + ", logSize=" + logSize + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicRequestTimeDetailVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicRequestTimeDetailVO.java new file mode 100644 index 00000000..c89c7cb2 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicRequestTimeDetailVO.java @@ -0,0 +1,113 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/8 + */ +@ApiModel(value = "Topic请求耗时详情") +public class TopicRequestTimeDetailVO { + @ApiModelProperty(value = "请求耗时类型") + private String requestTimeType; + + @ApiModelProperty(value = "responseQueueTimeMs") + private Object responseQueueTimeMs; + + @ApiModelProperty(value = "localTimeMs") + private Object localTimeMs; + + @ApiModelProperty(value = "requestQueueTimeMs") + private Object requestQueueTimeMs; + + @ApiModelProperty(value = "throttleTimeMs") + private Object throttleTimeMs; + + @ApiModelProperty(value = "responseSendTimeMs") + private Object responseSendTimeMs; + + @ApiModelProperty(value = "remoteTimeMs") + private Object remoteTimeMs; + + @ApiModelProperty(value = "totalTimeMs") + private Object totalTimeMs; + + public String getRequestTimeType() { + return requestTimeType; + } + + public void setRequestTimeType(String requestTimeType) { + this.requestTimeType = requestTimeType; + } + + public Object getResponseQueueTimeMs() { + return responseQueueTimeMs; + } + + public void setResponseQueueTimeMs(Object responseQueueTimeMs) { + this.responseQueueTimeMs = responseQueueTimeMs; + } + + public Object getLocalTimeMs() { + return localTimeMs; + } + + public void setLocalTimeMs(Object localTimeMs) { + this.localTimeMs = localTimeMs; + } + + public Object getRequestQueueTimeMs() { + return requestQueueTimeMs; + } + + public void setRequestQueueTimeMs(Object requestQueueTimeMs) { + this.requestQueueTimeMs = requestQueueTimeMs; + } + + public Object getThrottleTimeMs() { + return throttleTimeMs; + } + + public void setThrottleTimeMs(Object throttleTimeMs) { + this.throttleTimeMs = throttleTimeMs; + } + + public Object getResponseSendTimeMs() { + return responseSendTimeMs; + } + + public void setResponseSendTimeMs(Object responseSendTimeMs) { + this.responseSendTimeMs = responseSendTimeMs; + } + + public Object getRemoteTimeMs() { + return remoteTimeMs; + } + + public void setRemoteTimeMs(Object remoteTimeMs) { + this.remoteTimeMs = remoteTimeMs; + } + + public Object getTotalTimeMs() { + return totalTimeMs; + } + + public void setTotalTimeMs(Object totalTimeMs) { + this.totalTimeMs = totalTimeMs; + } + + @Override + public String toString() { + return "TopicRequestTimeDetailVO{" + + "requestTimeType='" + requestTimeType + '\'' + + ", responseQueueTimeMs=" + responseQueueTimeMs + + ", localTimeMs=" + localTimeMs + + ", requestQueueTimeMs=" + requestQueueTimeMs + + ", throttleTimeMs=" + throttleTimeMs + + ", responseSendTimeMs=" + responseSendTimeMs + + ", remoteTimeMs=" + remoteTimeMs + + ", totalTimeMs=" + totalTimeMs + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicRequestTimeVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicRequestTimeVO.java new file mode 100644 index 00000000..dfce225d --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicRequestTimeVO.java @@ -0,0 +1,149 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/7 + */ +@ApiModel(value = "Topic请求耗时信息") +public class TopicRequestTimeVO { + @ApiModelProperty(value = "produce请求平均耗时") + private Object produceRequestTimeMean; + + @ApiModelProperty(value = "produce请求50分位耗时") + private Object produceRequestTime50thPercentile; + + @ApiModelProperty(value = "produce请求75分位耗时") + private Object produceRequestTime75thPercentile; + + @ApiModelProperty(value = "produce请求95分位耗时") + private Object produceRequestTime95thPercentile; + + @ApiModelProperty(value = "produce请求99分位耗时") + private Object produceRequestTime99thPercentile; + + @ApiModelProperty(value = "fetch请求平均耗时") + private Object fetchRequestTimeMean; + + @ApiModelProperty(value = "fetch请求50分位耗时") + private Object fetchRequestTime50thPercentile; + + @ApiModelProperty(value = "fetch请求75分位耗时") + private Object fetchRequestTime75thPercentile; + + @ApiModelProperty(value = "fetch请求95分位耗时") + private Object fetchRequestTime95thPercentile; + + @ApiModelProperty(value = "fetch请求99分位耗时") + private Object fetchRequestTime99thPercentile; + + @ApiModelProperty(value = "创建时间") + private Object gmtCreate; + + public Object getProduceRequestTimeMean() { + return produceRequestTimeMean; + } + + public void setProduceRequestTimeMean(Object produceRequestTimeMean) { + this.produceRequestTimeMean = produceRequestTimeMean; + } + + public Object getProduceRequestTime50thPercentile() { + return produceRequestTime50thPercentile; + } + + public void setProduceRequestTime50thPercentile(Object produceRequestTime50thPercentile) { + this.produceRequestTime50thPercentile = produceRequestTime50thPercentile; + } + + public Object getProduceRequestTime75thPercentile() { + return produceRequestTime75thPercentile; + } + + public void setProduceRequestTime75thPercentile(Object produceRequestTime75thPercentile) { + this.produceRequestTime75thPercentile = produceRequestTime75thPercentile; + } + + public Object getProduceRequestTime95thPercentile() { + return produceRequestTime95thPercentile; + } + + public void setProduceRequestTime95thPercentile(Object produceRequestTime95thPercentile) { + this.produceRequestTime95thPercentile = produceRequestTime95thPercentile; + } + + public Object getProduceRequestTime99thPercentile() { + return produceRequestTime99thPercentile; + } + + public void setProduceRequestTime99thPercentile(Object produceRequestTime99thPercentile) { + this.produceRequestTime99thPercentile = produceRequestTime99thPercentile; + } + + public Object getFetchRequestTimeMean() { + return fetchRequestTimeMean; + } + + public void setFetchRequestTimeMean(Object fetchRequestTimeMean) { + this.fetchRequestTimeMean = fetchRequestTimeMean; + } + + public Object getFetchRequestTime50thPercentile() { + return fetchRequestTime50thPercentile; + } + + public void setFetchRequestTime50thPercentile(Object fetchRequestTime50thPercentile) { + this.fetchRequestTime50thPercentile = fetchRequestTime50thPercentile; + } + + public Object getFetchRequestTime75thPercentile() { + return fetchRequestTime75thPercentile; + } + + public void setFetchRequestTime75thPercentile(Object fetchRequestTime75thPercentile) { + this.fetchRequestTime75thPercentile = fetchRequestTime75thPercentile; + } + + public Object getFetchRequestTime95thPercentile() { + return fetchRequestTime95thPercentile; + } + + public void setFetchRequestTime95thPercentile(Object fetchRequestTime95thPercentile) { + this.fetchRequestTime95thPercentile = fetchRequestTime95thPercentile; + } + + public Object getFetchRequestTime99thPercentile() { + return fetchRequestTime99thPercentile; + } + + public void setFetchRequestTime99thPercentile(Object fetchRequestTime99thPercentile) { + this.fetchRequestTime99thPercentile = fetchRequestTime99thPercentile; + } + + public Object getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Object gmtCreate) { + this.gmtCreate = gmtCreate; + } + + @Override + public String toString() { + return "TopicRequestTimeVO{" + + "produceRequestTimeMean=" + produceRequestTimeMean + + ", produceRequestTime50thPercentile=" + produceRequestTime50thPercentile + + ", produceRequestTime75thPercentile=" + produceRequestTime75thPercentile + + ", produceRequestTime95thPercentile=" + produceRequestTime95thPercentile + + ", produceRequestTime99thPercentile=" + produceRequestTime99thPercentile + + ", fetchRequestTimeMean=" + fetchRequestTimeMean + + ", fetchRequestTime50thPercentile=" + fetchRequestTime50thPercentile + + ", fetchRequestTime75thPercentile=" + fetchRequestTime75thPercentile + + ", fetchRequestTime95thPercentile=" + fetchRequestTime95thPercentile + + ", fetchRequestTime99thPercentile=" + fetchRequestTime99thPercentile + + ", gmtCreate=" + gmtCreate + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicVO.java new file mode 100644 index 00000000..afb99025 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/normal/topic/TopicVO.java @@ -0,0 +1,113 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/8 + */ +@ApiModel(value = "Topic信息") +public class TopicVO { + @ApiModelProperty(value = "逻辑集群ID") + private Long clusterId; + + @ApiModelProperty(value = "逻辑集群名称") + private String clusterName; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "Topic描述") + private String description; + + @ApiModelProperty(value = "AppID") + private String appId; + + @ApiModelProperty(value = "App名称") + private String appName; + + @ApiModelProperty(value = "App负责人") + private String appPrincipals; + + @ApiModelProperty(value = "需要鉴权, true:是 false:否") + private Boolean needAuth; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppPrincipals() { + return appPrincipals; + } + + public void setAppPrincipals(String appPrincipals) { + this.appPrincipals = appPrincipals; + } + + public Boolean getNeedAuth() { + return needAuth; + } + + public void setNeedAuth(Boolean needAuth) { + this.needAuth = needAuth; + } + + @Override + public String toString() { + return "TopicVO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", description='" + description + '\'' + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", appPrincipals='" + appPrincipals + '\'' + + ", needAuth=" + needAuth + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/AnomalyFlowTopicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/AnomalyFlowTopicVO.java new file mode 100644 index 00000000..d057c913 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/AnomalyFlowTopicVO.java @@ -0,0 +1,101 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.expert; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/3/30 + */ +@ApiModel(description = "流量异常Topic") +public class AnomalyFlowTopicVO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "集群名称") + private String clusterName; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "bytesIn(B/s)") + private Double bytesIn; + + @ApiModelProperty(value = "bytesIn增加(B/s)") + private Double bytesInIncr; + + @ApiModelProperty(value = "iops(Q/s)") + private Double iops; + + @ApiModelProperty(value = "iops增加(Q/s)") + private Double iopsIncr; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Double getBytesIn() { + return bytesIn; + } + + public void setBytesIn(Double bytesIn) { + this.bytesIn = bytesIn; + } + + public Double getBytesInIncr() { + return bytesInIncr; + } + + public void setBytesInIncr(Double bytesInIncr) { + this.bytesInIncr = bytesInIncr; + } + + public Double getIops() { + return iops; + } + + public void setIops(Double iops) { + this.iops = iops; + } + + public Double getIopsIncr() { + return iopsIncr; + } + + public void setIopsIncr(Double iopsIncr) { + this.iopsIncr = iopsIncr; + } + + @Override + public String toString() { + return "AnomalyFlowTopic{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", bytesIn=" + bytesIn + + ", bytesInIncr=" + bytesInIncr + + ", iops=" + iops + + ", iopsIncr=" + iopsIncr + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/BrokerIdPartitionNumVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/BrokerIdPartitionNumVO.java new file mode 100644 index 00000000..413aa6a4 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/BrokerIdPartitionNumVO.java @@ -0,0 +1,41 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.expert; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/5/15 + */ +@ApiModel(description = "Region热点Topic") +public class BrokerIdPartitionNumVO { + @ApiModelProperty(value = "BrokerId") + private Integer brokeId; + + @ApiModelProperty(value = "分区数") + private Integer partitionNum; + + public Integer getBrokeId() { + return brokeId; + } + + public void setBrokeId(Integer brokeId) { + this.brokeId = brokeId; + } + + public Integer getPartitionNum() { + return partitionNum; + } + + public void setPartitionNum(Integer partitionNum) { + this.partitionNum = partitionNum; + } + + @Override + public String toString() { + return "BrokerIdPartitionNumVO{" + + "brokeId=" + brokeId + + ", partitionNum=" + partitionNum + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/ExpiredTopicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/ExpiredTopicVO.java new file mode 100644 index 00000000..46c7a3a2 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/ExpiredTopicVO.java @@ -0,0 +1,111 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.expert; + +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/3/30 + */ +public class ExpiredTopicVO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "集群名称") + private String clusterName; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "过期天数") + private Integer expiredDay; + + @ApiModelProperty(value = "App名称") + private String appName; + + @ApiModelProperty(value = "AppID") + private String appId; + + @ApiModelProperty(value = "负责人") + private String principals; + + @ApiModelProperty(value = "状态, -1:可下线, 0:过期待通知, 1+:已通知待反馈") + private Integer status; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getExpiredDay() { + return expiredDay; + } + + public void setExpiredDay(Integer expiredDay) { + this.expiredDay = expiredDay; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getPrincipals() { + return principals; + } + + public void setPrincipals(String principals) { + this.principals = principals; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + @Override + public String toString() { + return "ExpiredTopicVO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", expiredDay=" + expiredDay + + ", appName='" + appName + '\'' + + ", appId='" + appId + '\'' + + ", principals='" + principals + '\'' + + ", status=" + status + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/PartitionInsufficientTopicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/PartitionInsufficientTopicVO.java new file mode 100644 index 00000000..fd135052 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/PartitionInsufficientTopicVO.java @@ -0,0 +1,127 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.expert; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/3/30 + */ +@ApiModel(description = "分区不足Topic") +public class PartitionInsufficientTopicVO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "集群名称") + private String clusterName; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "Region名称") + private String regionName; + + @ApiModelProperty(value = "Topic所属BrokerId列表") + private List brokerIdList; + + @ApiModelProperty(value = "当前分区数") + private Integer presentPartitionNum; + + @ApiModelProperty(value = "建议分区数") + private Integer suggestedPartitionNum; + + @ApiModelProperty(value = "单分区流量(B/s)") + private Double bytesInPerPartition; + + @ApiModelProperty(value = "今天,昨天,前天的峰值均值流入流量(B/s)") + private List maxAvgBytesInList; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getRegionName() { + return regionName; + } + + public void setRegionName(String regionName) { + this.regionName = regionName; + } + + public List getBrokerIdList() { + return brokerIdList; + } + + public void setBrokerIdList(List brokerIdList) { + this.brokerIdList = brokerIdList; + } + + public Integer getPresentPartitionNum() { + return presentPartitionNum; + } + + public void setPresentPartitionNum(Integer presentPartitionNum) { + this.presentPartitionNum = presentPartitionNum; + } + + public Integer getSuggestedPartitionNum() { + return suggestedPartitionNum; + } + + public void setSuggestedPartitionNum(Integer suggestedPartitionNum) { + this.suggestedPartitionNum = suggestedPartitionNum; + } + + public Double getBytesInPerPartition() { + return bytesInPerPartition; + } + + public void setBytesInPerPartition(Double bytesInPerPartition) { + this.bytesInPerPartition = bytesInPerPartition; + } + + public List getMaxAvgBytesInList() { + return maxAvgBytesInList; + } + + public void setMaxAvgBytesInList(List maxAvgBytesInList) { + this.maxAvgBytesInList = maxAvgBytesInList; + } + + @Override + public String toString() { + return "PartitionInsufficientTopicVO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", regionName='" + regionName + '\'' + + ", brokerIdList=" + brokerIdList + + ", presentPartitionNum=" + presentPartitionNum + + ", suggestedPartitionNum=" + suggestedPartitionNum + + ", bytesInPerPartition=" + bytesInPerPartition + + ", maxAvgBytesInList=" + maxAvgBytesInList + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/RegionHotTopicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/RegionHotTopicVO.java new file mode 100644 index 00000000..70e44fff --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/expert/RegionHotTopicVO.java @@ -0,0 +1,85 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.expert; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/3/20 + */ +@ApiModel(description = "Region热点Topic") +public class RegionHotTopicVO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "集群名称") + private String clusterName; + +// @ApiModelProperty(value = "RegionID") +// private Long regionId; +// +// @ApiModelProperty(value = "Region名称") +// private String regionName; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "失衡详情") + private List detailList; + + @ApiModelProperty(value = "Topic保存时间") + private Long retentionTime; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public List getDetailList() { + return detailList; + } + + public void setDetailList(List detailList) { + this.detailList = detailList; + } + + public Long getRetentionTime() { + return retentionTime; + } + + public void setRetentionTime(Long retentionTime) { + this.retentionTime = retentionTime; + } + + @Override + public String toString() { + return "RegionHotTopicVO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", detailList=" + detailList + + ", retentionTime=" + retentionTime + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignPartitionStatusVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignPartitionStatusVO.java new file mode 100644 index 00000000..51e1bda6 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignPartitionStatusVO.java @@ -0,0 +1,53 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.reassign; + +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/4/16 + */ +public class ReassignPartitionStatusVO { + @ApiModelProperty(value = "分区Id") + private Integer partitionId; + + @ApiModelProperty(value = "目标副本ID列表") + private List destReplicaIdList; + + @ApiModelProperty(value = "状态") + private Integer status; + + public Integer getPartitionId() { + return partitionId; + } + + public void setPartitionId(Integer partitionId) { + this.partitionId = partitionId; + } + + public List getDestReplicaIdList() { + return destReplicaIdList; + } + + public void setDestReplicaIdList(List destReplicaIdList) { + this.destReplicaIdList = destReplicaIdList; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + @Override + public String toString() { + return "ReassignPartitionStatusVO{" + + "partitionId=" + partitionId + + ", destReplicaIdList=" + destReplicaIdList + + ", status=" + status + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignTaskVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignTaskVO.java new file mode 100644 index 00000000..294ea1ef --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignTaskVO.java @@ -0,0 +1,136 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.reassign; + +import io.swagger.annotations.ApiModelProperty; + +/** + * 迁移任务 + * @author zengqiao + * @date 19/7/13 + */ +public class ReassignTaskVO { + @ApiModelProperty(value = "任务ID") + private Long taskId; + + @ApiModelProperty(value = "任务名称") + private String taskName; + + @ApiModelProperty(value = "完成数") + private Integer completedTopicNum; + + @ApiModelProperty(value = "总数") + private Integer totalTopicNum; + + @ApiModelProperty(value = "状态") + private Integer status; + + @ApiModelProperty(value = "计划开始时间") + private Long beginTime; + + @ApiModelProperty(value = "实际结束时间") + private Long endTime; + + @ApiModelProperty(value = "任务创建时间") + private Long gmtCreate; + + @ApiModelProperty(value = "操作人") + private String operator; + + @ApiModelProperty(value = "任务说明") + private String description; + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getTaskName() { + return taskName; + } + + public void setTaskName(String taskName) { + this.taskName = taskName; + } + + public Integer getCompletedTopicNum() { + return completedTopicNum; + } + + public void setCompletedTopicNum(Integer completedTopicNum) { + this.completedTopicNum = completedTopicNum; + } + + public Integer getTotalTopicNum() { + return totalTopicNum; + } + + public void setTotalTopicNum(Integer totalTopicNum) { + this.totalTopicNum = totalTopicNum; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Long getBeginTime() { + return beginTime; + } + + public void setBeginTime(Long beginTime) { + this.beginTime = beginTime; + } + + public Long getEndTime() { + return endTime; + } + + public void setEndTime(Long endTime) { + this.endTime = endTime; + } + + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "ReassignTaskVO{" + + "taskId=" + taskId + + ", taskName='" + taskName + '\'' + + ", completedTopicNum=" + completedTopicNum + + ", totalTopicNum=" + totalTopicNum + + ", status=" + status + + ", beginTime=" + beginTime + + ", endTime=" + endTime + + ", gmtCreate=" + gmtCreate + + ", operator='" + operator + '\'' + + ", description='" + description + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignTopicStatusVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignTopicStatusVO.java new file mode 100644 index 00000000..836e4108 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/reassign/ReassignTopicStatusVO.java @@ -0,0 +1,151 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.reassign; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/4/16 + */ +@ApiModel(value = "Topic迁移信息") +public class ReassignTopicStatusVO { + @ApiModelProperty(value = "子任务ID") + private Long subTaskId; + + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "集群名称") + private String clusterName; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "状态") + private Integer status; + + @ApiModelProperty(value = "实际限流(B/s)") + private Long realThrottle; + + @ApiModelProperty(value = "限流上限(B/s)") + private Long maxThrottle; + + @ApiModelProperty(value = "限流下限(B/s)") + private Long minThrottle; + + @ApiModelProperty(value = "完成迁移分区数") + private Integer completedPartitionNum; + + @ApiModelProperty(value = "总的分区数") + private Integer totalPartitionNum; + + @ApiModelProperty(value = "分区迁移列表") + private List reassignList; + + public Long getSubTaskId() { + return subTaskId; + } + + public void setSubTaskId(Long subTaskId) { + this.subTaskId = subTaskId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Long getRealThrottle() { + return realThrottle; + } + + public void setRealThrottle(Long realThrottle) { + this.realThrottle = realThrottle; + } + + public Long getMaxThrottle() { + return maxThrottle; + } + + public void setMaxThrottle(Long maxThrottle) { + this.maxThrottle = maxThrottle; + } + + public Long getMinThrottle() { + return minThrottle; + } + + public void setMinThrottle(Long minThrottle) { + this.minThrottle = minThrottle; + } + + public Integer getCompletedPartitionNum() { + return completedPartitionNum; + } + + public void setCompletedPartitionNum(Integer completedPartitionNum) { + this.completedPartitionNum = completedPartitionNum; + } + + public Integer getTotalPartitionNum() { + return totalPartitionNum; + } + + public void setTotalPartitionNum(Integer totalPartitionNum) { + this.totalPartitionNum = totalPartitionNum; + } + + public List getReassignList() { + return reassignList; + } + + public void setReassignList(List reassignList) { + this.reassignList = reassignList; + } + + @Override + public String toString() { + return "ReassignTopicStatusVO{" + + "subTaskId=" + subTaskId + + ", clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", status=" + status + + ", realThrottle=" + realThrottle + + ", maxThrottle=" + maxThrottle + + ", minThrottle=" + minThrottle + + ", completedPartitionNum=" + completedPartitionNum + + ", totalPartitionNum=" + totalPartitionNum + + ", reassignList=" + reassignList + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskKafkaFilesVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskKafkaFilesVO.java new file mode 100644 index 00000000..0fde414d --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskKafkaFilesVO.java @@ -0,0 +1,49 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.task; + +import io.swagger.annotations.ApiModel; + +/** + * @author zengqiao + * @date 20/5/11 + */ +@ApiModel(value="Kafka相关文件") +public class ClusterTaskKafkaFilesVO { + private String fileName; + + private String fileMd5; + + private Integer fileType; + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getFileMd5() { + return fileMd5; + } + + public void setFileMd5(String fileMd5) { + this.fileMd5 = fileMd5; + } + + public Integer getFileType() { + return fileType; + } + + public void setFileType(Integer fileType) { + this.fileType = fileType; + } + + @Override + public String toString() { + return "ClusterTaskKafkaFilesVO{" + + "fileName='" + fileName + '\'' + + ", fileMd5='" + fileMd5 + '\'' + + ", fileType=" + fileType + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskMetadataVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskMetadataVO.java new file mode 100644 index 00000000..2788f197 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskMetadataVO.java @@ -0,0 +1,187 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/4/27 + */ +@ApiModel(value="任务元信息") +public class ClusterTaskMetadataVO { + @ApiModelProperty(value="任务ID") + private Long taskId; + + @ApiModelProperty(value="集群ID") + private Long clusterId; + + @ApiModelProperty(value="集群名称") + private String clusterName; + + @ApiModelProperty(value="升级的主机列表") + private List hostList; + + @ApiModelProperty(value="升级的主机暂停点") + private List pauseHostList; + + @ApiModelProperty(value="回滚主机列表") + private List rollbackHostList; + + @ApiModelProperty(value="回滚主机暂停点") + private List rollbackPauseHostList; + + @ApiModelProperty(value="kafka包名") + private String kafkaPackageName; + + @ApiModelProperty(value="kafka包 MD5") + private String kafkaPackageMd5; + + @ApiModelProperty(value="server配置文件Id") + private Long serverPropertiesFileId; + + @ApiModelProperty(value="server配置名") + private String serverPropertiesName; + + @ApiModelProperty(value="server配置 MD5") + private String serverPropertiesMd5; + + @ApiModelProperty(value="操作人") + private String operator; + + @ApiModelProperty(value="创建时间") + private Long gmtCreate; + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public List getHostList() { + return hostList; + } + + public void setHostList(List hostList) { + this.hostList = hostList; + } + + public List getPauseHostList() { + return pauseHostList; + } + + public void setPauseHostList(List pauseHostList) { + this.pauseHostList = pauseHostList; + } + + public List getRollbackHostList() { + return rollbackHostList; + } + + public void setRollbackHostList(List rollbackHostList) { + this.rollbackHostList = rollbackHostList; + } + + public List getRollbackPauseHostList() { + return rollbackPauseHostList; + } + + public void setRollbackPauseHostList(List rollbackPauseHostList) { + this.rollbackPauseHostList = rollbackPauseHostList; + } + + public String getKafkaPackageName() { + return kafkaPackageName; + } + + public void setKafkaPackageName(String kafkaPackageName) { + this.kafkaPackageName = kafkaPackageName; + } + + public String getKafkaPackageMd5() { + return kafkaPackageMd5; + } + + public void setKafkaPackageMd5(String kafkaPackageMd5) { + this.kafkaPackageMd5 = kafkaPackageMd5; + } + + public Long getServerPropertiesFileId() { + return serverPropertiesFileId; + } + + public void setServerPropertiesFileId(Long serverPropertiesFileId) { + this.serverPropertiesFileId = serverPropertiesFileId; + } + + public String getServerPropertiesName() { + return serverPropertiesName; + } + + public void setServerPropertiesName(String serverPropertiesName) { + this.serverPropertiesName = serverPropertiesName; + } + + public String getServerPropertiesMd5() { + return serverPropertiesMd5; + } + + public void setServerPropertiesMd5(String serverPropertiesMd5) { + this.serverPropertiesMd5 = serverPropertiesMd5; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } + + @Override + public String toString() { + return "ClusterTaskMetadataVO{" + + "taskId=" + taskId + + ", clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", hostList=" + hostList + + ", pauseHostList=" + pauseHostList + + ", rollbackHostList=" + rollbackHostList + + ", rollbackPauseHostList=" + rollbackPauseHostList + + ", kafkaPackageName='" + kafkaPackageName + '\'' + + ", kafkaPackageMd5='" + kafkaPackageMd5 + '\'' + + ", serverPropertiesFileId=" + serverPropertiesFileId + + ", serverPropertiesName='" + serverPropertiesName + '\'' + + ", serverPropertiesMd5='" + serverPropertiesMd5 + '\'' + + ", operator='" + operator + '\'' + + ", gmtCreate=" + gmtCreate + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskStatusVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskStatusVO.java new file mode 100644 index 00000000..b780737b --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskStatusVO.java @@ -0,0 +1,127 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/4/27 + */ +@ApiModel(value="任务状态详情") +public class ClusterTaskStatusVO { + @ApiModelProperty(value="任务ID") + private Long taskId; + + @ApiModelProperty(value="任务状态: 30:运行中(展示暂停), 40:暂停(展示开始), 100:完成(都置灰)") + private Integer status; + + @ApiModelProperty(value="正处于回滚的状态") + private Boolean rollback; + + @ApiModelProperty(value="任务总数") + private Integer sumCount; + + @ApiModelProperty(value="成功总数") + private Integer successCount; + + @ApiModelProperty(value="失败总数") + private Integer failedCount; + + @ApiModelProperty(value="执行中总数") + private Integer runningCount; + + @ApiModelProperty(value="等待总数") + private Integer waitingCount; + + @ApiModelProperty(value="子任务状态") + private List subTaskStatusList; + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Boolean getRollback() { + return rollback; + } + + public void setRollback(Boolean rollback) { + this.rollback = rollback; + } + + public Integer getSumCount() { + return sumCount; + } + + public void setSumCount(Integer sumCount) { + this.sumCount = sumCount; + } + + public Integer getSuccessCount() { + return successCount; + } + + public void setSuccessCount(Integer successCount) { + this.successCount = successCount; + } + + public Integer getFailedCount() { + return failedCount; + } + + public void setFailedCount(Integer failedCount) { + this.failedCount = failedCount; + } + + public Integer getRunningCount() { + return runningCount; + } + + public void setRunningCount(Integer runningCount) { + this.runningCount = runningCount; + } + + public Integer getWaitingCount() { + return waitingCount; + } + + public void setWaitingCount(Integer waitingCount) { + this.waitingCount = waitingCount; + } + + public List getSubTaskStatusList() { + return subTaskStatusList; + } + + public void setSubTaskStatusList(List subTaskStatusList) { + this.subTaskStatusList = subTaskStatusList; + } + + @Override + public String toString() { + return "ClusterTaskStatusVO{" + + "taskId=" + taskId + + ", status=" + status + + ", rollback=" + rollback + + ", sumCount=" + sumCount + + ", successCount=" + successCount + + ", failedCount=" + failedCount + + ", runningCount=" + runningCount + + ", waitingCount=" + waitingCount + + ", subTaskStatusList=" + subTaskStatusList + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskSubStatusVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskSubStatusVO.java new file mode 100644 index 00000000..3f6e17d3 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskSubStatusVO.java @@ -0,0 +1,65 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/27 + */ +@ApiModel(value="子任务状态") +public class ClusterTaskSubStatusVO { + @ApiModelProperty(value="主机名") + private String hostname; + + @ApiModelProperty(value="子任务状态") + private Integer status; + + @ApiModelProperty(value="角色") + private String kafkaRoles; + + @ApiModelProperty(value="分组ID") + private Integer groupId; + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getKafkaRoles() { + return kafkaRoles; + } + + public void setKafkaRoles(String kafkaRoles) { + this.kafkaRoles = kafkaRoles; + } + + public Integer getGroupId() { + return groupId; + } + + public void setGroupId(Integer groupId) { + this.groupId = groupId; + } + + @Override + public String toString() { + return "ClusterTaskSubStatusVO{" + + "hostname='" + hostname + '\'' + + ", status=" + status + + ", kafkaRoles='" + kafkaRoles + '\'' + + ", groupId=" + groupId + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskVO.java new file mode 100644 index 00000000..239de98e --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/op/task/ClusterTaskVO.java @@ -0,0 +1,99 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.op.task; + +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/21 + */ +public class ClusterTaskVO { + @ApiModelProperty(value="任务Id") + private Long taskId; + + @ApiModelProperty(value="集群ID") + private Long clusterId; + + @ApiModelProperty(value="集群名称") + private String clusterName; + + @ApiModelProperty(value="任务类型") + private String taskType; + + @ApiModelProperty(value="状态") + private Integer status; + + @ApiModelProperty(value="操作人") + private String operator; + + @ApiModelProperty(value="创建时间") + private Long createTime; + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTaskType() { + return taskType; + } + + public void setTaskType(String taskType) { + this.taskType = taskType; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public Long getCreateTime() { + return createTime; + } + + public void setCreateTime(Long createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "ClusterTaskVO{" + + "taskId=" + taskId + + ", clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", taskType='" + taskType + '\'' + + ", status=" + status + + ", operator='" + operator + '\'' + + ", createTime=" + createTime + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/ConfigVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/ConfigVO.java new file mode 100644 index 00000000..b4bef9a8 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/ConfigVO.java @@ -0,0 +1,89 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/3/19 + */ +@ApiModel(value = "ConfigVO", description = "配置信息") +public class ConfigVO { + @ApiModelProperty(value="集群Id") + private Long id; + + @ApiModelProperty(value="配置键") + private String configKey; + + @ApiModelProperty(value="配置值") + private String configValue; + + @ApiModelProperty(value="描述信息") + private String configDescription; + + @ApiModelProperty(value="创建时间") + private Long gmtCreate; + + @ApiModelProperty(value="修改时间") + private Long gmtModify; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getConfigKey() { + return configKey; + } + + public void setConfigKey(String configKey) { + this.configKey = configKey; + } + + public String getConfigValue() { + return configValue; + } + + public void setConfigValue(String configValue) { + this.configValue = configValue; + } + + public String getConfigDescription() { + return configDescription; + } + + public void setConfigDescription(String configDescription) { + this.configDescription = configDescription; + } + + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Long getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Long gmtModify) { + this.gmtModify = gmtModify; + } + + @Override + public String toString() { + return "ConfigVO{" + + "id=" + id + + ", configKey='" + configKey + '\'' + + ", configValue='" + configValue + '\'' + + ", configDescription='" + configDescription + '\'' + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/CustomScheduledTaskVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/CustomScheduledTaskVO.java new file mode 100644 index 00000000..2132abc2 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/CustomScheduledTaskVO.java @@ -0,0 +1,35 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd; + +/** + * @author zengqiao + * @date 20/8/11 + */ +public class CustomScheduledTaskVO { + private String name; + + private Object cron; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Object getCron() { + return cron; + } + + public void setCron(Object cron) { + this.cron = cron; + } + + @Override + public String toString() { + return "CustomScheduledTaskVO{" + + "name='" + name + '\'' + + ", cron=" + cron + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/KafkaControllerVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/KafkaControllerVO.java new file mode 100644 index 00000000..1c205fcb --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/KafkaControllerVO.java @@ -0,0 +1,65 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author huangyiminghappy@163.com + * @date 2019-03-27 + */ +@ApiModel(value = "KafkaController信息") +public class KafkaControllerVO { + @ApiModelProperty(value = "节点ID") + private Integer brokerId; + + @ApiModelProperty(value = "节点地址") + private String host; + + @ApiModelProperty(value = "ZK消息版本") + private Integer version; + + @ApiModelProperty(value = "变更时间") + private Long timestamp; + + public Integer getBrokerId() { + return brokerId; + } + + public void setBrokerId(Integer brokerId) { + this.brokerId = brokerId; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + @Override + public String toString() { + return "KafkaControllerVO{" + + "brokerId=" + brokerId + + ", host='" + host + '\'' + + ", version=" + version + + ", timestamp=" + timestamp + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/KafkaFileVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/KafkaFileVO.java new file mode 100644 index 00000000..1ca29b73 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/KafkaFileVO.java @@ -0,0 +1,127 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/4/29 + */ +@ApiModel(description = "Kafka文件信息") +public class KafkaFileVO { + @ApiModelProperty(value = "集群名称") + private String clusterName; + + @ApiModelProperty(value = "ID") + private Long id; + + @ApiModelProperty(value = "文件名称") + private String fileName; + + @ApiModelProperty(value = "文件类型") + private Integer fileType; + + @ApiModelProperty(value = "存储位置") + private String storageName; + + @ApiModelProperty(value = "文件MD5") + private String fileMd5; + + @ApiModelProperty(value = "操作人") + private String operator; + + @ApiModelProperty(value = "备注") + private String description; + + @ApiModelProperty(value = "修改时间") + private Date gmtModify; + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public Integer getFileType() { + return fileType; + } + + public void setFileType(Integer fileType) { + this.fileType = fileType; + } + + public String getStorageName() { + return storageName; + } + + public void setStorageName(String storageName) { + this.storageName = storageName; + } + + public String getFileMd5() { + return fileMd5; + } + + public void setFileMd5(String fileMd5) { + this.fileMd5 = fileMd5; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + @Override + public String toString() { + return "KafkaFileVO{" + + "clusterName='" + clusterName + '\'' + + ", id=" + id + + ", fileName='" + fileName + '\'' + + ", fileType=" + fileType + + ", storageName='" + storageName + '\'' + + ", fileMd5='" + fileMd5 + '\'' + + ", operator='" + operator + '\'' + + ", description='" + description + '\'' + + ", gmtModify=" + gmtModify + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/OperateRecordVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/OperateRecordVO.java new file mode 100644 index 00000000..576c6f53 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/OperateRecordVO.java @@ -0,0 +1,139 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/09/03 + */ +@ApiModel(description = "操作记录") +public class OperateRecordVO { + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("模块ID") + private Integer moduleId; + + @ApiModelProperty("模块") + private String module; + + @ApiModelProperty("操作ID") + private Integer operateId; + + @ApiModelProperty("操作") + private String operate; + + @ApiModelProperty("资源(app、topic)") + private String resource; + + @ApiModelProperty("操作内容") + private String content; + + @ApiModelProperty("操作人") + private String operator; + + @ApiModelProperty("创建时间") + private Long createTime; + + @ApiModelProperty("修改时间") + private Long modifyTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getModuleId() { + return moduleId; + } + + public void setModuleId(Integer moduleId) { + this.moduleId = moduleId; + } + + public String getModule() { + return module; + } + + public void setModule(String module) { + this.module = module; + } + + public Integer getOperateId() { + return operateId; + } + + public void setOperateId(Integer operateId) { + this.operateId = operateId; + } + + public String getOperate() { + return operate; + } + + public void setOperate(String operate) { + this.operate = operate; + } + + public String getResource() { + return resource; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public Long getCreateTime() { + return createTime; + } + + public void setCreateTime(Long createTime) { + this.createTime = createTime; + } + + public Long getModifyTime() { + return modifyTime; + } + + public void setModifyTime(Long modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "OperateRecordVO{" + + "id=" + id + + ", moduleId=" + moduleId + + ", module='" + module + '\'' + + ", operateId=" + operateId + + ", operate='" + operate + '\'' + + ", resource='" + resource + '\'' + + ", content='" + content + '\'' + + ", operator='" + operator + '\'' + + ", createTime=" + createTime + + ", modifyTime=" + modifyTime + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/RdTopicBasicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/RdTopicBasicVO.java new file mode 100644 index 00000000..55682938 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/RdTopicBasicVO.java @@ -0,0 +1,115 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.Properties; + +/** + * @author zengqiao + * @date 20/6/10 + */ +@ApiModel(description = "Topic基本信息(RD视角)") +public class RdTopicBasicVO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "集群名称") + private String clusterName; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "保留时间(ms)") + private Long retentionTime; + + @ApiModelProperty(value = "应用ID") + private String appId; + + @ApiModelProperty(value = "应用名称") + private String appName; + + @ApiModelProperty(value = "Topic属性") + private Properties properties; + + @ApiModelProperty(value = "备注") + private String description; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Long getRetentionTime() { + return retentionTime; + } + + public void setRetentionTime(Long retentionTime) { + this.retentionTime = retentionTime; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties properties) { + this.properties = properties; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "RdTopicBasicVO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", topicName='" + topicName + '\'' + + ", retentionTime=" + retentionTime + + ", appId='" + appId + '\'' + + ", appName='" + appName + '\'' + + ", properties=" + properties + + ", description='" + description + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/RegionVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/RegionVO.java similarity index 53% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/RegionVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/RegionVO.java index d57567cb..e51b2738 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/RegionVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/RegionVO.java @@ -1,8 +1,9 @@ -package com.xiaojukeji.kafka.manager.web.vo; +package com.xiaojukeji.kafka.manager.common.entity.vo.rd; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import java.util.Date; import java.util.List; /** @@ -10,19 +11,16 @@ import java.util.List; * @author zengqiao * @date 19/4/1 */ -@ApiModel(value = "RegionVO", description = "Region信息") +@ApiModel(description = "Region信息") public class RegionVO { @ApiModelProperty(value = "RegionID") - protected Long regionId; + protected Long id; @ApiModelProperty(value = "集群ID") private Long clusterId; - @ApiModelProperty(value = "region名称") - private String regionName; - - @ApiModelProperty(value = "重要级别, 0:普通, 1:重要,2:重要") - private Integer level; + @ApiModelProperty(value = "Region名称") + private String name; @ApiModelProperty(value = "brokerId列表") private List brokerIdList; @@ -30,24 +28,30 @@ public class RegionVO { @ApiModelProperty(value = "描述信息") private String description; - @ApiModelProperty(value = "操作人") - private String operator; - - @ApiModelProperty(value = "状态, -1:废弃 0:正常 1:容量已满") + @ApiModelProperty(value = "状态, 0:正常 1:容量已满") private Integer status; + @ApiModelProperty(value = "容量(B/s)") + private Long capacity; + + @ApiModelProperty(value = "实际流量(B/s)") + private Long realUsed; + + @ApiModelProperty(value = "预估流量(B/s)") + private Long estimateUsed; + @ApiModelProperty(value = "创建时间") - private Long gmtCreate; + private Date gmtCreate; @ApiModelProperty(value = "修改时间") - private Long gmtModify; + private Date gmtModify; - public Long getRegionId() { - return regionId; + public Long getId() { + return id; } - public void setRegionId(Long regionId) { - this.regionId = regionId; + public void setId(Long id) { + this.id = id; } public Long getClusterId() { @@ -58,20 +62,12 @@ public class RegionVO { this.clusterId = clusterId; } - public String getRegionName() { - return regionName; + public String getName() { + return name; } - public void setRegionName(String regionName) { - this.regionName = regionName; - } - - public Integer getLevel() { - return level; - } - - public void setLevel(Integer level) { - this.level = level; + public void setName(String name) { + this.name = name; } public List getBrokerIdList() { @@ -90,14 +86,6 @@ public class RegionVO { this.description = description; } - public String getOperator() { - return operator; - } - - public void setOperator(String operator) { - this.operator = operator; - } - public Integer getStatus() { return status; } @@ -106,33 +94,58 @@ public class RegionVO { this.status = status; } - public Long getGmtCreate() { + public Long getCapacity() { + return capacity; + } + + public void setCapacity(Long capacity) { + this.capacity = capacity; + } + + public Long getRealUsed() { + return realUsed; + } + + public void setRealUsed(Long realUsed) { + this.realUsed = realUsed; + } + + public Long getEstimateUsed() { + return estimateUsed; + } + + public void setEstimateUsed(Long estimateUsed) { + this.estimateUsed = estimateUsed; + } + + public Date getGmtCreate() { return gmtCreate; } - public void setGmtCreate(Long gmtCreate) { + public void setGmtCreate(Date gmtCreate) { this.gmtCreate = gmtCreate; } - public Long getGmtModify() { + public Date getGmtModify() { return gmtModify; } - public void setGmtModify(Long gmtModify) { + public void setGmtModify(Date gmtModify) { this.gmtModify = gmtModify; } @Override public String toString() { return "RegionVO{" + - "regionId=" + regionId + + "id=" + id + ", clusterId=" + clusterId + - ", regionName='" + regionName + '\'' + - ", level=" + level + + ", name='" + name + '\'' + ", brokerIdList=" + brokerIdList + ", description='" + description + '\'' + - ", operator='" + operator + '\'' + ", status=" + status + + ", capacity=" + capacity + + ", realUsed=" + realUsed + + ", estimateUsed=" + estimateUsed + ", gmtCreate=" + gmtCreate + ", gmtModify=" + gmtModify + '}'; diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicBrokerVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/TopicBrokerVO.java similarity index 74% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicBrokerVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/TopicBrokerVO.java index f2641925..ae7ae9ec 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/topic/TopicBrokerVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/TopicBrokerVO.java @@ -1,6 +1,5 @@ -package com.xiaojukeji.kafka.manager.web.vo.topic; +package com.xiaojukeji.kafka.manager.common.entity.vo.rd; -import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.util.List; @@ -10,8 +9,10 @@ import java.util.List; * @author zengqiao * @date 19/4/3 */ -@ApiModel(value = "TopicBroker信息") public class TopicBrokerVO { + @ApiModelProperty(value = "物理集群ID") + private Long clusterId; + @ApiModelProperty(value = "brokerId") private Integer brokerId; @@ -27,6 +28,17 @@ public class TopicBrokerVO { @ApiModelProperty(value = "leader分区的Id") private List leaderPartitionIdList; + @ApiModelProperty(value = "是否存活") + private boolean alive; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + public Integer getBrokerId() { return brokerId; } @@ -67,14 +79,24 @@ public class TopicBrokerVO { this.leaderPartitionIdList = leaderPartitionIdList; } + public boolean isAlive() { + return alive; + } + + public void setAlive(boolean alive) { + this.alive = alive; + } + @Override public String toString() { return "TopicBrokerVO{" + - "brokerId=" + brokerId + + "clusterId=" + clusterId + + ", brokerId=" + brokerId + ", host='" + host + '\'' + ", partitionNum=" + partitionNum + ", partitionIdList=" + partitionIdList + ", leaderPartitionIdList=" + leaderPartitionIdList + + ", alive=" + alive + '}'; } } diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/AnalysisBrokerVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/AnalysisBrokerVO.java similarity index 97% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/AnalysisBrokerVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/AnalysisBrokerVO.java index 4a0837e0..accc60ba 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/AnalysisBrokerVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/AnalysisBrokerVO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.broker; +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.broker; import java.util.List; diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/AnalysisTopicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/AnalysisTopicVO.java similarity index 98% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/AnalysisTopicVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/AnalysisTopicVO.java index 9cae6d8c..d2a20213 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/AnalysisTopicVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/AnalysisTopicVO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.broker; +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.broker; /** * @author zengqiao diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerBasicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerBasicVO.java similarity index 89% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerBasicVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerBasicVO.java index f993e7b7..6754ece7 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerBasicVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerBasicVO.java @@ -1,16 +1,14 @@ -package com.xiaojukeji.kafka.manager.web.vo.broker; +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.broker; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import java.io.Serializable; - /** * @author huangjw * @date 17/6/1. */ -@ApiModel(value = "BrokerBasicInfoVO", description = "账号信息") -public class BrokerBasicVO implements Serializable { +@ApiModel(description = "Broker基本信息") +public class BrokerBasicVO { @ApiModelProperty(value = "主机名") private String host; @@ -90,7 +88,7 @@ public class BrokerBasicVO implements Serializable { @Override public String toString() { - return "BrokerBasicInfoVO{" + + return "BrokerBasicVO{" + "host='" + host + '\'' + ", port=" + port + ", jmxPort=" + jmxPort + diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerDiskTopicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerDiskTopicVO.java new file mode 100644 index 00000000..d75f9f20 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerDiskTopicVO.java @@ -0,0 +1,115 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.broker; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/4/30 + */ +@ApiModel(description = "Broker磁盘信息") +public class BrokerDiskTopicVO { + @ApiModelProperty(value = "集群ID") + private Long clusterId; + + @ApiModelProperty(value = "Topic名称") + private String topicName; + + @ApiModelProperty(value = "BrokerID") + private Integer brokerId; + + @ApiModelProperty(value = "磁盘名") + private String diskName; + + @ApiModelProperty(value = "Leader分区") + private List leaderPartitions; + + @ApiModelProperty(value = "Follow分区") + private List followerPartitions; + + @ApiModelProperty(value = "处于同步状态") + private Boolean underReplicated; + + @ApiModelProperty(value = "未处于同步状态的分区") + private List notUnderReplicatedPartitions; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public Integer getBrokerId() { + return brokerId; + } + + public void setBrokerId(Integer brokerId) { + this.brokerId = brokerId; + } + + public String getDiskName() { + return diskName; + } + + public void setDiskName(String diskName) { + this.diskName = diskName; + } + + public List getLeaderPartitions() { + return leaderPartitions; + } + + public void setLeaderPartitions(List leaderPartitions) { + this.leaderPartitions = leaderPartitions; + } + + public List getFollowerPartitions() { + return followerPartitions; + } + + public void setFollowerPartitions(List followerPartitions) { + this.followerPartitions = followerPartitions; + } + + public Boolean getUnderReplicated() { + return underReplicated; + } + + public void setUnderReplicated(Boolean underReplicated) { + this.underReplicated = underReplicated; + } + + public List getNotUnderReplicatedPartitions() { + return notUnderReplicatedPartitions; + } + + public void setNotUnderReplicatedPartitions(List notUnderReplicatedPartitions) { + this.notUnderReplicatedPartitions = notUnderReplicatedPartitions; + } + + @Override + public String toString() { + return "BrokerDiskTopicVO{" + + "clusterId=" + clusterId + + ", topicName='" + topicName + '\'' + + ", brokerId=" + brokerId + + ", diskName='" + diskName + '\'' + + ", leaderPartitions=" + leaderPartitions + + ", followerPartitions=" + followerPartitions + + ", underReplicated=" + underReplicated + + ", notUnderReplicatedPartitions=" + notUnderReplicatedPartitions + + '}'; + } +} \ No newline at end of file diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerMetadataVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerMetadataVO.java similarity index 92% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerMetadataVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerMetadataVO.java index f1fddfb4..a9d3950b 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerMetadataVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerMetadataVO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.web.vo.broker; +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.broker; /** * @author zengqiao diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerMetricsVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerMetricsVO.java new file mode 100644 index 00000000..a77992cf --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerMetricsVO.java @@ -0,0 +1,221 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.broker; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 2019-06-03 + */ +@ApiModel(description = "Broker指标") +public class BrokerMetricsVO { + @ApiModelProperty(value = "健康分[0-100]") + private Integer healthScore; + + @ApiModelProperty(value = "流入流量(B/s)") + private Object bytesInPerSec; + + @ApiModelProperty(value = "流出流量(B/s)") + private Object bytesOutPerSec; + + @ApiModelProperty(value = "被拒绝流量(B/s)") + private Object bytesRejectedPerSec; + + @ApiModelProperty(value = "消息数") + private Object messagesInPerSec; + + @ApiModelProperty(value = "发送请求数") + private Object produceRequestPerSec; + + @ApiModelProperty(value = "消费请求数") + private Object fetchConsumerRequestPerSec; + + @ApiModelProperty(value = "请求处理器空闲百分比") + private Object requestHandlerIdlPercent; + + @ApiModelProperty(value = "网络处理器空闲百分比") + private Object networkProcessorIdlPercent; + + @ApiModelProperty(value = "请求队列大小") + private Integer requestQueueSize; + + @ApiModelProperty(value = "响应队列大小") + private Integer responseQueueSize; + + @ApiModelProperty(value = "刷日志事件") + private Object logFlushTime; + + @ApiModelProperty(value = "每秒消费失败数") + private Object failFetchRequestPerSec; + + @ApiModelProperty(value = "每秒发送失败数") + private Object failProduceRequestPerSec; + + @ApiModelProperty(value = "发送耗时99分位") + private Object totalTimeProduce99Th; + + @ApiModelProperty(value = "消费耗时99分位") + private Object totalTimeFetchConsumer99Th; + + @ApiModelProperty(value = "创建时间") + private Long gmtCreate; + + public Integer getHealthScore() { + return healthScore; + } + + public void setHealthScore(Integer healthScore) { + this.healthScore = healthScore; + } + + public Object getBytesInPerSec() { + return bytesInPerSec; + } + + public void setBytesInPerSec(Object bytesInPerSec) { + this.bytesInPerSec = bytesInPerSec; + } + + public Object getBytesOutPerSec() { + return bytesOutPerSec; + } + + public void setBytesOutPerSec(Object bytesOutPerSec) { + this.bytesOutPerSec = bytesOutPerSec; + } + + public Object getBytesRejectedPerSec() { + return bytesRejectedPerSec; + } + + public void setBytesRejectedPerSec(Object bytesRejectedPerSec) { + this.bytesRejectedPerSec = bytesRejectedPerSec; + } + + public Object getMessagesInPerSec() { + return messagesInPerSec; + } + + public void setMessagesInPerSec(Object messagesInPerSec) { + this.messagesInPerSec = messagesInPerSec; + } + + public Object getProduceRequestPerSec() { + return produceRequestPerSec; + } + + public void setProduceRequestPerSec(Object produceRequestPerSec) { + this.produceRequestPerSec = produceRequestPerSec; + } + + public Object getFetchConsumerRequestPerSec() { + return fetchConsumerRequestPerSec; + } + + public void setFetchConsumerRequestPerSec(Object fetchConsumerRequestPerSec) { + this.fetchConsumerRequestPerSec = fetchConsumerRequestPerSec; + } + + public Object getRequestHandlerIdlPercent() { + return requestHandlerIdlPercent; + } + + public void setRequestHandlerIdlPercent(Object requestHandlerIdlPercent) { + this.requestHandlerIdlPercent = requestHandlerIdlPercent; + } + + public Object getNetworkProcessorIdlPercent() { + return networkProcessorIdlPercent; + } + + public void setNetworkProcessorIdlPercent(Object networkProcessorIdlPercent) { + this.networkProcessorIdlPercent = networkProcessorIdlPercent; + } + + public Integer getRequestQueueSize() { + return requestQueueSize; + } + + public void setRequestQueueSize(Integer requestQueueSize) { + this.requestQueueSize = requestQueueSize; + } + + public Integer getResponseQueueSize() { + return responseQueueSize; + } + + public void setResponseQueueSize(Integer responseQueueSize) { + this.responseQueueSize = responseQueueSize; + } + + public Object getLogFlushTime() { + return logFlushTime; + } + + public void setLogFlushTime(Object logFlushTime) { + this.logFlushTime = logFlushTime; + } + + public Object getFailFetchRequestPerSec() { + return failFetchRequestPerSec; + } + + public void setFailFetchRequestPerSec(Object failFetchRequestPerSec) { + this.failFetchRequestPerSec = failFetchRequestPerSec; + } + + public Object getFailProduceRequestPerSec() { + return failProduceRequestPerSec; + } + + public void setFailProduceRequestPerSec(Object failProduceRequestPerSec) { + this.failProduceRequestPerSec = failProduceRequestPerSec; + } + + public Object getTotalTimeProduce99Th() { + return totalTimeProduce99Th; + } + + public void setTotalTimeProduce99Th(Object totalTimeProduce99Th) { + this.totalTimeProduce99Th = totalTimeProduce99Th; + } + + public Object getTotalTimeFetchConsumer99Th() { + return totalTimeFetchConsumer99Th; + } + + public void setTotalTimeFetchConsumer99Th(Object totalTimeFetchConsumer99Th) { + this.totalTimeFetchConsumer99Th = totalTimeFetchConsumer99Th; + } + + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } + + @Override + public String toString() { + return "BrokerMetricsVO{" + + "healthScore=" + healthScore + + ", bytesInPerSec=" + bytesInPerSec + + ", bytesOutPerSec=" + bytesOutPerSec + + ", bytesRejectedPerSec=" + bytesRejectedPerSec + + ", messagesInPerSec=" + messagesInPerSec + + ", produceRequestPerSec=" + produceRequestPerSec + + ", fetchConsumerRequestPerSec=" + fetchConsumerRequestPerSec + + ", requestHandlerIdlPercent=" + requestHandlerIdlPercent + + ", networkProcessorIdlPercent=" + networkProcessorIdlPercent + + ", requestQueueSize=" + requestQueueSize + + ", responseQueueSize=" + responseQueueSize + + ", logFlushTime=" + logFlushTime + + ", failFetchRequestPerSec=" + failFetchRequestPerSec + + ", failProduceRequestPerSec=" + failProduceRequestPerSec + + ", totalTimeProduce99Th=" + totalTimeProduce99Th + + ", totalTimeFetchConsumer99Th=" + totalTimeFetchConsumer99Th + + ", gmtCreate=" + gmtCreate + + '}'; + } +} diff --git a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerPartitionsVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerPartitionVO.java similarity index 89% rename from web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerPartitionsVO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerPartitionVO.java index ce4c935c..6a35161e 100644 --- a/web/src/main/java/com/xiaojukeji/kafka/manager/web/vo/broker/BrokerPartitionsVO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/BrokerPartitionVO.java @@ -1,17 +1,16 @@ -package com.xiaojukeji.kafka.manager.web.vo.broker; +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.broker; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import java.io.Serializable; import java.util.List; /** * @author zengqiao * @date 19/4/22 */ -@ApiModel(value = "BrokerPartitionsVO", description = "Broker分区信息") -public class BrokerPartitionsVO implements Serializable { +@ApiModel(description = "Broker分区信息") +public class BrokerPartitionVO { @ApiModelProperty(value = "Topic名称") private String topicName; @@ -69,7 +68,7 @@ public class BrokerPartitionsVO implements Serializable { @Override public String toString() { - return "BrokerPartitionsVO{" + + return "BrokerPartitionVO{" + "topicName='" + topicName + '\'' + ", leaderPartitionList=" + leaderPartitionList + ", followerPartitionIdList=" + followerPartitionIdList + diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/RdBrokerBasicVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/RdBrokerBasicVO.java new file mode 100644 index 00000000..d09a2785 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/broker/RdBrokerBasicVO.java @@ -0,0 +1,53 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.broker; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zhongyuankai + * @date 2020/6/11 + */ +@ApiModel(description = "Broker基本信息") +public class RdBrokerBasicVO { + @ApiModelProperty(value = "brokerId") + private Integer brokerId; + + @ApiModelProperty(value = "主机名") + private String host; + + @ApiModelProperty(value = "逻辑集群") + private Long logicClusterId; + + public Integer getBrokerId() { + return brokerId; + } + + public void setBrokerId(Integer brokerId) { + this.brokerId = brokerId; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public Long getLogicClusterId() { + return logicClusterId; + } + + public void setLogicClusterId(Long logicClusterId) { + this.logicClusterId = logicClusterId; + } + + @Override + public String toString() { + return "RdBrokerBasicVO{" + + "brokerId=" + brokerId + + ", host='" + host + '\'' + + ", logicClusterId=" + logicClusterId + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterBaseVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterBaseVO.java new file mode 100644 index 00000000..ca2b7350 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterBaseVO.java @@ -0,0 +1,151 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.cluster; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.Date; + +/** + * @author zengqiao + * @date 20/4/16 + */ +@ApiModel(description="集群信息") +public class ClusterBaseVO { + @ApiModelProperty(value="集群Id") + private Long clusterId; + + @ApiModelProperty(value="集群名称") + private String clusterName; + + @ApiModelProperty(value="ZK地址") + private String zookeeper; + + @ApiModelProperty(value="bootstrap地址") + private String bootstrapServers; + + @ApiModelProperty(value="kafka版本") + private String kafkaVersion; + + @ApiModelProperty(value="数据中心") + private String idc; + + @ApiModelProperty(value="集群类型") + private Integer mode; + + @ApiModelProperty(value="安全配置参数") + private String securityProperties; + + @ApiModelProperty(value="1:监控中, 0:暂停监控") + private Integer status; + + @ApiModelProperty(value="接入时间") + private Date gmtCreate; + + @ApiModelProperty(value="修改时间") + private Date gmtModify; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getZookeeper() { + return zookeeper; + } + + public void setZookeeper(String zookeeper) { + this.zookeeper = zookeeper; + } + + public String getBootstrapServers() { + return bootstrapServers; + } + + public void setBootstrapServers(String bootstrapServers) { + this.bootstrapServers = bootstrapServers; + } + + public String getKafkaVersion() { + return kafkaVersion; + } + + public void setKafkaVersion(String kafkaVersion) { + this.kafkaVersion = kafkaVersion; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public Integer getMode() { + return mode; + } + + public void setMode(Integer mode) { + this.mode = mode; + } + + public String getSecurityProperties() { + return securityProperties; + } + + public void setSecurityProperties(String securityProperties) { + this.securityProperties = securityProperties; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + @Override + public String toString() { + return "ClusterBaseVO{" + + "clusterId=" + clusterId + + ", clusterName='" + clusterName + '\'' + + ", zookeeper='" + zookeeper + '\'' + + ", bootstrapServers='" + bootstrapServers + '\'' + + ", kafkaVersion='" + kafkaVersion + '\'' + + ", idc='" + idc + '\'' + + ", mode='" + mode + '\'' + + ", securityProperties='" + securityProperties + '\'' + + ", status=" + status + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterBrokerStatusVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterBrokerStatusVO.java new file mode 100644 index 00000000..a98ab766 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterBrokerStatusVO.java @@ -0,0 +1,43 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.cluster; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/5/11 + */ +@ApiModel(description="集群Broker状态") +public class ClusterBrokerStatusVO { + @ApiModelProperty(value = "Broker副本同步状态: 总数, 已同步数, 未同步数") + private List brokerReplicaStatusList; + + @ApiModelProperty(value = "Broker峰值状态: 总数, 60-%, 60-80%, 80-100%, 100+%, 异常") + private List brokerBytesInStatusList; + + public List getBrokerReplicaStatusList() { + return brokerReplicaStatusList; + } + + public void setBrokerReplicaStatusList(List brokerReplicaStatusList) { + this.brokerReplicaStatusList = brokerReplicaStatusList; + } + + public List getBrokerBytesInStatusList() { + return brokerBytesInStatusList; + } + + public void setBrokerBytesInStatusList(List brokerBytesInStatusList) { + this.brokerBytesInStatusList = brokerBytesInStatusList; + } + + @Override + public String toString() { + return "ClusterBrokerStatusVO{" + + "brokerReplicaStatusList=" + brokerReplicaStatusList + + ", brokerBytesInStatusList=" + brokerBytesInStatusList + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterDetailVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterDetailVO.java new file mode 100644 index 00000000..cdeb7da7 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/ClusterDetailVO.java @@ -0,0 +1,77 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.cluster; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zengqiao + * @date 20/4/23 + */ +@ApiModel(description="集群信息") +public class ClusterDetailVO extends ClusterBaseVO { + @ApiModelProperty(value="Broker数") + private Integer brokerNum; + + @ApiModelProperty(value="Topic数") + private Integer topicNum; + + @ApiModelProperty(value="ConsumerGroup数") + private Integer consumerGroupNum; + + @ApiModelProperty(value="ControllerID") + private Integer controllerId; + + @ApiModelProperty(value="Region数") + private Integer regionNum; + + public Integer getBrokerNum() { + return brokerNum; + } + + public void setBrokerNum(Integer brokerNum) { + this.brokerNum = brokerNum; + } + + public Integer getTopicNum() { + return topicNum; + } + + public void setTopicNum(Integer topicNum) { + this.topicNum = topicNum; + } + + public Integer getConsumerGroupNum() { + return consumerGroupNum; + } + + public void setConsumerGroupNum(Integer consumerGroupNum) { + this.consumerGroupNum = consumerGroupNum; + } + + public Integer getControllerId() { + return controllerId; + } + + public void setControllerId(Integer controllerId) { + this.controllerId = controllerId; + } + + public Integer getRegionNum() { + return regionNum; + } + + public void setRegionNum(Integer regionNum) { + this.regionNum = regionNum; + } + + @Override + public String toString() { + return "ClusterDetailVO{" + + "brokerNum=" + brokerNum + + ", topicNum=" + topicNum + + ", consumerGroupNum=" + consumerGroupNum + + ", controllerId=" + controllerId + + ", regionNum=" + regionNum + + "} " + super.toString(); + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/LogicalClusterVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/LogicalClusterVO.java new file mode 100644 index 00000000..86ced10f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/LogicalClusterVO.java @@ -0,0 +1,128 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.cluster; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.Date; +import java.util.List; + +/** + * @author zengqiao + * @date 20/6/29 + */ +@ApiModel(description = "逻辑集群") +public class LogicalClusterVO { + @ApiModelProperty(value = "逻辑集群ID") + protected Long logicalClusterId; + + @ApiModelProperty(value = "逻辑集群名称") + private String logicalClusterName; + + @ApiModelProperty(value = "物理集群ID") + private Long physicalClusterId; + + @ApiModelProperty(value = "brokerId列表") + private List regionIdList; + + @ApiModelProperty(value = "逻辑集群类型") + private Integer mode; + + @ApiModelProperty(value = "所属应用") + private String appId; + + @ApiModelProperty(value = "描述信息") + private String description; + + @ApiModelProperty(value = "创建时间") + private Date gmtCreate; + + @ApiModelProperty(value = "修改时间") + private Date gmtModify; + + public Long getLogicalClusterId() { + return logicalClusterId; + } + + public void setLogicalClusterId(Long logicalClusterId) { + this.logicalClusterId = logicalClusterId; + } + + public String getLogicalClusterName() { + return logicalClusterName; + } + + public void setLogicalClusterName(String logicalClusterName) { + this.logicalClusterName = logicalClusterName; + } + + public Long getPhysicalClusterId() { + return physicalClusterId; + } + + public void setPhysicalClusterId(Long physicalClusterId) { + this.physicalClusterId = physicalClusterId; + } + + public List getRegionIdList() { + return regionIdList; + } + + public void setRegionIdList(List regionIdList) { + this.regionIdList = regionIdList; + } + + public Integer getMode() { + return mode; + } + + public void setMode(Integer mode) { + this.mode = mode; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Date gmtCreate) { + this.gmtCreate = gmtCreate; + } + + public Date getGmtModify() { + return gmtModify; + } + + public void setGmtModify(Date gmtModify) { + this.gmtModify = gmtModify; + } + + @Override + public String toString() { + return "LogicalClusterVO{" + + "logicalClusterId=" + logicalClusterId + + ", logicalClusterName='" + logicalClusterName + '\'' + + ", physicalClusterId=" + physicalClusterId + + ", regionIdList=" + regionIdList + + ", mode=" + mode + + ", appId='" + appId + '\'' + + ", description='" + description + '\'' + + ", gmtCreate=" + gmtCreate + + ", gmtModify=" + gmtModify + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/RdClusterMetricsVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/RdClusterMetricsVO.java new file mode 100644 index 00000000..df15b96b --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/rd/cluster/RdClusterMetricsVO.java @@ -0,0 +1,111 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.rd.cluster; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * ClusterMetricsVO + * @author zengqiao + * @date 19/4/3 + */ +@ApiModel(description="集群流量信息") +public class RdClusterMetricsVO { + @ApiModelProperty(value="集群Id") + private Long clusterId; + + @ApiModelProperty(value="Topic数量") + private Object topicNum; + + @ApiModelProperty(value="Partition数量") + private Object partitionNum; + + @ApiModelProperty(value="Broker数量") + private Object brokerNum; + + @ApiModelProperty(value="每秒流入的字节数") + private Object bytesInPerSec; + + @ApiModelProperty(value="每秒流出的字节数") + private Object bytesOutPerSec; + + @ApiModelProperty(value="每秒拒绝的字节数") + private Object bytesRejectedPerSec; + + @ApiModelProperty(value="每秒流入的消息数") + private Object messagesInPerSec; + + @ApiModelProperty(value="创建时间") + private Long gmtCreate; + + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public Object getTopicNum() { + return topicNum; + } + + public void setTopicNum(Object topicNum) { + this.topicNum = topicNum; + } + + public Object getPartitionNum() { + return partitionNum; + } + + public void setPartitionNum(Object partitionNum) { + this.partitionNum = partitionNum; + } + + public Object getBrokerNum() { + return brokerNum; + } + + public void setBrokerNum(Object brokerNum) { + this.brokerNum = brokerNum; + } + + public Object getBytesInPerSec() { + return bytesInPerSec; + } + + public void setBytesInPerSec(Object bytesInPerSec) { + this.bytesInPerSec = bytesInPerSec; + } + + public Object getBytesOutPerSec() { + return bytesOutPerSec; + } + + public void setBytesOutPerSec(Object bytesOutPerSec) { + this.bytesOutPerSec = bytesOutPerSec; + } + + public Object getBytesRejectedPerSec() { + return bytesRejectedPerSec; + } + + public void setBytesRejectedPerSec(Object bytesRejectedPerSec) { + this.bytesRejectedPerSec = bytesRejectedPerSec; + } + + public Object getMessagesInPerSec() { + return messagesInPerSec; + } + + public void setMessagesInPerSec(Object messagesInPerSec) { + this.messagesInPerSec = messagesInPerSec; + } + + public Long getGmtCreate() { + return gmtCreate; + } + + public void setGmtCreate(Long gmtCreate) { + this.gmtCreate = gmtCreate; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/thirdpart/AppBasicInfoVO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/thirdpart/AppBasicInfoVO.java new file mode 100644 index 00000000..dd43df2e --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/vo/thirdpart/AppBasicInfoVO.java @@ -0,0 +1,90 @@ +package com.xiaojukeji.kafka.manager.common.entity.vo.thirdpart; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author zhongyuankai + * @date 2020/6/18 + */ +@Deprecated +@ApiModel(description="AppID基本信息") +public class AppBasicInfoVO { + @ApiModelProperty(value="appId") + private String appId; + + @ApiModelProperty(value="app密码") + private String password; + + @ApiModelProperty(value="app名称") + private String name; + + @ApiModelProperty(value="申请人") + private String applicant; + + @ApiModelProperty(value="appId负责人") + private String principal; + + @ApiModelProperty(value="描述信息") + private String description; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getApplicant() { + return applicant; + } + + public void setApplicant(String applicant) { + this.applicant = applicant; + } + + public String getPrincipal() { + return principal; + } + + public void setPrincipal(String principal) { + this.principal = principal; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "AppBasicInfoVO{" + + "appId='" + appId + '\'' + + ", password='" + password + '\'' + + ", name='" + name + '\'' + + ", applicant='" + applicant + '\'' + + ", principal='" + principal + '\'' + + ", description='" + description + '\'' + + '}'; + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/ConsumerMetricsCollectedEvent.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/ConsumerMetricsCollectedEvent.java new file mode 100644 index 00000000..9aa45d8f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/ConsumerMetricsCollectedEvent.java @@ -0,0 +1,23 @@ +package com.xiaojukeji.kafka.manager.common.events; + +import com.xiaojukeji.kafka.manager.common.entity.metrics.ConsumerMetrics; +import org.springframework.context.ApplicationEvent; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/8/31 + */ +public class ConsumerMetricsCollectedEvent extends ApplicationEvent { + private List metricsList; + + public ConsumerMetricsCollectedEvent(Object source, List metricsList) { + super(source); + this.metricsList = metricsList; + } + + public List getMetricsList() { + return metricsList; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderApplyEvent.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderApplyEvent.java new file mode 100644 index 00000000..a71fa88f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderApplyEvent.java @@ -0,0 +1,13 @@ +package com.xiaojukeji.kafka.manager.common.events; + +import com.xiaojukeji.kafka.manager.common.entity.pojo.OrderDO; + +/** + * @author zengqiao + * @date 20/09/03 + */ +public class OrderApplyEvent extends OrderEvent { + public OrderApplyEvent(Object source, OrderDO orderDO, String idc) { + super(source, orderDO, idc); + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderEvent.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderEvent.java new file mode 100644 index 00000000..ef3311ee --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderEvent.java @@ -0,0 +1,28 @@ +package com.xiaojukeji.kafka.manager.common.events; + +import com.xiaojukeji.kafka.manager.common.entity.pojo.OrderDO; +import org.springframework.context.ApplicationEvent; + +/** + * @author zengqiao + * @date 20/8/27 + */ +public abstract class OrderEvent extends ApplicationEvent { + private OrderDO orderDO; + + private String idc; + + public OrderEvent(Object source, OrderDO orderDO, String idc) { + super(source); + this.orderDO = orderDO; + this.idc = idc; + } + + public OrderDO getOrderDO() { + return orderDO; + } + + public String getIdc() { + return idc; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderPassedEvent.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderPassedEvent.java new file mode 100644 index 00000000..21af0821 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderPassedEvent.java @@ -0,0 +1,16 @@ +package com.xiaojukeji.kafka.manager.common.events; + +import com.xiaojukeji.kafka.manager.common.entity.ao.account.Account; +import com.xiaojukeji.kafka.manager.common.entity.pojo.OrderDO; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/09/03 + */ +public class OrderPassedEvent extends OrderEvent { + public OrderPassedEvent(Object source, OrderDO orderDO, String idc, List accountList) { + super(source, orderDO, idc); + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderRefusedEvent.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderRefusedEvent.java new file mode 100644 index 00000000..4066915f --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/OrderRefusedEvent.java @@ -0,0 +1,16 @@ +package com.xiaojukeji.kafka.manager.common.events; + +import com.xiaojukeji.kafka.manager.common.entity.ao.account.Account; +import com.xiaojukeji.kafka.manager.common.entity.pojo.OrderDO; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/09/03 + */ +public class OrderRefusedEvent extends OrderEvent { + public OrderRefusedEvent(Object source, OrderDO orderDO, String idc, List accountList) { + super(source, orderDO, idc); + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/TopicMetricsCollectedEvent.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/TopicMetricsCollectedEvent.java new file mode 100644 index 00000000..4ed78ee5 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/events/TopicMetricsCollectedEvent.java @@ -0,0 +1,30 @@ +package com.xiaojukeji.kafka.manager.common.events; + +import com.xiaojukeji.kafka.manager.common.entity.metrics.TopicMetrics; +import org.springframework.context.ApplicationEvent; + +import java.util.List; + +/** + * @author zengqiao + * @date 20/8/31 + */ +public class TopicMetricsCollectedEvent extends ApplicationEvent { + private Long clusterId; + + private List metricsList; + + public TopicMetricsCollectedEvent(Object source, Long clusterId, List metricsList) { + super(source); + this.clusterId = clusterId; + this.metricsList = metricsList; + } + + public List getMetricsList() { + return metricsList; + } + + public Long getClusterId() { + return clusterId; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/exception/ConfigException.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/exception/ConfigException.java similarity index 100% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/exception/ConfigException.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/exception/ConfigException.java diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/exception/CopyException.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/exception/CopyException.java similarity index 100% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/exception/CopyException.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/exception/CopyException.java diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/CopyUtils.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/CopyUtils.java similarity index 99% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/CopyUtils.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/CopyUtils.java index 946b6272..bef175e4 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/CopyUtils.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/CopyUtils.java @@ -18,7 +18,7 @@ import java.util.concurrent.ConcurrentHashMap; public class CopyUtils { @SuppressWarnings({"unchecked", "rawtypes"}) - public static T deepCopy(T obj) { + private static T deepCopy(T obj) { if (obj == null) { return null; } else if (obj instanceof String) { diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DateUtils.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DateUtils.java new file mode 100644 index 00000000..d4fa72a4 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DateUtils.java @@ -0,0 +1,91 @@ +package com.xiaojukeji.kafka.manager.common.utils; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +/** + * 日期工具 + * @author huangyiminghappy@163.com + * @date 2019-03-20 + */ +public class DateUtils { + public static Date long2Date(Long time){ + return new Date(time); + } + + /** + * 获取nDay的起始时间 + */ + public static Long getDayStarTime(int nDay) { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.DAY_OF_MONTH, nDay); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return calendar.getTime().getTime(); + } + + /** + * 任意日期所在月的第一天的起始时间 + * @param date 任意日期 + * @author zengqiao + * @date 19/10/30 + * @return java.util.Date + */ + public static Date getMonthStartTime(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.set( + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH), + 0, + 0, + 0 + ); + calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH)); + return calendar.getTime(); + } + + /** + * 任意日期所在月的最后一天的最后时间 + * @param date 任意日期 + * @author zengqiao + * @date 19/10/30 + * @return java.util.Date + */ + public static Date getMonthEndTime(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.set( + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH) + 1, + calendar.get(Calendar.DAY_OF_MONTH), + 0, + 0, + 0 + ); + calendar.set(Calendar.MILLISECOND, calendar.getActualMinimum(Calendar.MILLISECOND)); + calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH)); + calendar.add(Calendar.MILLISECOND, -1); + return calendar.getTime(); + } + + public static String getFormattedDate(Date date) { + return new SimpleDateFormat("yyyy-MM-dd").format(date.getTime()); + } + + public static String getFormattedDate(Date date, String format) { + return new SimpleDateFormat(format).format(date.getTime()); + } + + public static String getFormattedDate(Long timestamp) { + return new SimpleDateFormat("yyyy-MM-dd").format(timestamp); + } + + public static Integer compare(Date t1, Date t2){ + return Long.compare(t1.getTime(), t2.getTime()); + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EasyApiLimitUtils.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EasyApiLimitUtils.java new file mode 100644 index 00000000..8589c95a --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EasyApiLimitUtils.java @@ -0,0 +1,69 @@ +package com.xiaojukeji.kafka.manager.common.utils; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +/** + * 宽松API请求限制工具 + * @author zengqiao + * @date 20/7/23 + */ +public class EasyApiLimitUtils { + private static final Long MAX_LIMIT_NUM = 10000L; + + private static final Long DEFAULT_DURATION_TIME = 24 * 60 * 60 * 1000L; + + private static final Map API_RECORD_MAP = new ConcurrentHashMap<>(); + + public static boolean incIfNotOverFlow(String key, long maxNum) { + AtomicLong atomicLong = API_RECORD_MAP.get(key); + if (atomicLong == null) { + API_RECORD_MAP.putIfAbsent(key, new AtomicLong(System.currentTimeMillis() * MAX_LIMIT_NUM)); + } + + while (true) { + atomicLong = API_RECORD_MAP.get(key); + + long value = atomicLong.longValue(); + long timestamp = value / MAX_LIMIT_NUM; + long presentNum = value % MAX_LIMIT_NUM; + if (System.currentTimeMillis() - timestamp < DEFAULT_DURATION_TIME && presentNum > maxNum) { + // 以及超过限制了 + return false; + } + + long newValue = System.currentTimeMillis() * MAX_LIMIT_NUM + 1; + if (System.currentTimeMillis() - timestamp < DEFAULT_DURATION_TIME && presentNum <= maxNum) { + newValue = timestamp * MAX_LIMIT_NUM + presentNum + 1; + } + + if (atomicLong.compareAndSet(value, newValue)) { + return true; + } + } + } + + public static void decIfNotOverFlow(String key) { + AtomicLong atomicLong = API_RECORD_MAP.get(key); + if (atomicLong == null) { + API_RECORD_MAP.putIfAbsent(key, new AtomicLong(System.currentTimeMillis() * MAX_LIMIT_NUM)); + } + + while (true) { + atomicLong = API_RECORD_MAP.get(key); + + long value = atomicLong.longValue(); + long timestamp = value / MAX_LIMIT_NUM; + long presentNum = value % MAX_LIMIT_NUM; + if (presentNum == 0) { + return; + } + + long newValue = timestamp * MAX_LIMIT_NUM + presentNum - 1; + if (atomicLong.compareAndSet(value, newValue)) { + return; + } + } + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EncryptUtil.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EncryptUtil.java similarity index 91% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EncryptUtil.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EncryptUtil.java index adfe6f37..1052eb12 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EncryptUtil.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/EncryptUtil.java @@ -12,8 +12,11 @@ public class EncryptUtil { }; public static String md5(String key) { + return md5(key.getBytes()); + } + + public static String md5(byte[] btInput) { try { - byte[] btInput = key.getBytes(); MessageDigest mdInst = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/HttpUtils.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/HttpUtils.java new file mode 100644 index 00000000..c15a25b4 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/HttpUtils.java @@ -0,0 +1,242 @@ +package com.xiaojukeji.kafka.manager.common.utils; + +import org.apache.http.HttpEntity; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.Map; + + +/** + * @author zengqiao + * @date 20/5/24 + */ +public class HttpUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(HttpUtils.class); + + // 连接超时时间, 单位: ms + private static int CONNECT_TIME_OUT = 15000; + + // 读取超时时间, 单位: ms + private static int READ_TIME_OUT = 2000; + + private static final String METHOD_GET = "GET"; + private static final String METHOD_POST = "POST"; + private static final String METHOD_PUT = "PUT"; + + private static final String CHARSET_UTF8 = "UTF-8"; + + private static final String FILE_PARAM = "filecontent"; + + private static final HttpClient HTTP_CLIENT = HttpClients.createDefault(); + + public static String get(String url, Map params) { + return sendRequest(url, METHOD_GET, params, null, null); + } + + public static String get(String url, Map params, Map headers) { + return sendRequest(url, METHOD_GET, params, headers, null); + } + + public static String postForString(String url, String content, Map headers) { + InputStream in = null; + try { + if (content != null && !content.isEmpty()) { + in = new ByteArrayInputStream(content.getBytes(CHARSET_UTF8)); + } + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + return sendRequest(url, METHOD_POST, null, headers, in); + } + + public static String uploadFile(String url, + MultipartFile multipartFile, + Map bodies, + Map headers) { + HttpPost post = new HttpPost(url); + String response = ""; + try { + + if (!ValidateUtils.isEmptyMap(headers)) { + for (Map.Entry e : headers.entrySet()) { + post.addHeader(e.getKey(), e.getValue()); + } + } + + MultipartEntityBuilder builder = MultipartEntityBuilder.create(); + builder.setCharset(Charset.forName(CHARSET_UTF8)); + + //加上此行代码解决返回中文乱码问题 + builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + + // 文件流 + builder.addBinaryBody( + FILE_PARAM, + multipartFile.getInputStream(), + ContentType.MULTIPART_FORM_DATA, + multipartFile.getOriginalFilename() + ); + + if (!ValidateUtils.isNull(bodies)) { + for (Map.Entry e : bodies.entrySet()) { + builder.addTextBody(e.getKey(), e.getValue()); + } + } + HttpEntity postEntity = builder.build(); + post.setEntity(postEntity); + HttpEntity entity = HTTP_CLIENT.execute(post).getEntity(); + response = EntityUtils.toString(entity, CHARSET_UTF8); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + post.releaseConnection(); + } + return response; + } + + public static String putForString(String url, String content, Map headers) { + InputStream in = null; + try { + if (content != null && !content.isEmpty()) { + in = new ByteArrayInputStream(content.getBytes(CHARSET_UTF8)); + } + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + return sendRequest(url, METHOD_PUT, null, headers, in); + } + + /** + * @param url 请求的链接, 只支持 http 和 https 链接 + * @param method GET or POST + * @param headers 请求头 (将覆盖默认请求), 可以为 null + * @param bodyStream 请求内容, 流将自动关闭, 可以为 null + * @return 返回响应内容的文本 + * @throws Exception http 响应 code 非 200, 或发生其他异常均抛出异常 + */ + private static String sendRequest(String url, + String method, + Map params, + Map headers, + InputStream bodyStream) { + HttpURLConnection conn = null; + try { + String paramUrl = setUrlParams(url, params); + + // 打开链接 + URL urlObj = new URL(paramUrl); + conn = (HttpURLConnection) urlObj.openConnection(); + + // 设置conn属性 + setConnProperties(conn, method, headers); + + // 设置请求内容 + if (bodyStream != null) { + conn.setDoOutput(true); + copyStreamAndClose(bodyStream, conn.getOutputStream()); + } + + return handleResponseBodyToString(conn.getInputStream()); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + closeConnection(conn); + } + } + + private static String setUrlParams(String url, Map params) { + if (url == null || params == null || params.isEmpty()) { + return url; + } + + StringBuilder sb = new StringBuilder(url).append('?'); + for (Map.Entry entry : params.entrySet()) { + sb.append(entry.getKey()).append('=').append(entry.getValue()).append('&'); + } + return sb.deleteCharAt(sb.length() - 1).toString(); + } + + private static void setConnProperties(HttpURLConnection conn, + String method, + Map headers) throws Exception { + // 设置连接超时时间 + conn.setConnectTimeout(CONNECT_TIME_OUT); + + // 设置读取超时时间 + conn.setReadTimeout(READ_TIME_OUT); + + // 设置请求方法 + if (method != null && !method.isEmpty()) { + conn.setRequestMethod(method); + } + + // 添加请求头 + conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); + if (headers == null || headers.isEmpty()) { + return; + } + for (Map.Entry entry : headers.entrySet()) { + conn.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + + private static String handleResponseBodyToString(InputStream in) throws Exception { + ByteArrayOutputStream bytesOut = null; + try { + bytesOut = new ByteArrayOutputStream(); + copyStreamAndClose(in, bytesOut); + return new String(bytesOut.toByteArray(), CHARSET_UTF8); + } finally { + closeStream(bytesOut); + } + } + + private static void copyStreamAndClose(InputStream in, OutputStream out) { + try { + byte[] buf = new byte[1024]; + int len = -1; + while ((len = in.read(buf)) != -1) { + out.write(buf, 0, len); + } + out.flush(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + closeStream(in); + closeStream(out); + } + } + + private static void closeConnection(HttpURLConnection conn) { + if (conn != null) { + try { + conn.disconnect(); + } catch (Exception e) { + LOGGER.error("close connection failed", e); + } + } + } + + private static void closeStream(Closeable stream) { + if (stream != null) { + try { + stream.close(); + } catch (Exception e) { + LOGGER.error("close stream failed", e); + } + } + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/JsonUtils.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/JsonUtils.java new file mode 100644 index 00000000..5daaece0 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/JsonUtils.java @@ -0,0 +1,51 @@ +package com.xiaojukeji.kafka.manager.common.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializeConfig; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +/** + * @author zengqiao + * @date 20/4/23 + */ +public class JsonUtils { + private static final String ENUM_METHOD_VALUES = "values"; + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + public static Object toJson(Class clazz) { + try { + Method method = clazz.getMethod(ENUM_METHOD_VALUES); + Object invoke = method.invoke(null); + + int length = java.lang.reflect.Array.getLength(invoke); + List values = new ArrayList(); + for (int i = 0; i < length; i++) { + values.add(java.lang.reflect.Array.get(invoke, i)); + } + SerializeConfig config = new SerializeConfig(); + config.configEnumAsJavaBean(clazz); + return JSON.parseArray(JSON.toJSONString(values, config)); + } catch (Exception e) { + } + return ""; + } + + public static Object toJson(Enum obj) { + try { + SerializeConfig config = new SerializeConfig(); + config.configEnumAsJavaBean(obj.getClass()); + return JSON.parseObject(JSON.toJSONString(obj, config)); + } catch (Exception e) { + } + return ""; + } + + public static String toJSONString(Object obj) { + return JSON.toJSONString(obj); + } +} \ No newline at end of file diff --git a/service/src/main/java/com/xiaojukeji/kafka/manager/service/utils/ListUtils.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/ListUtils.java similarity index 82% rename from service/src/main/java/com/xiaojukeji/kafka/manager/service/utils/ListUtils.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/ListUtils.java index 3215b3c5..f7ab020f 100644 --- a/service/src/main/java/com/xiaojukeji/kafka/manager/service/utils/ListUtils.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/ListUtils.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.service.utils; +package com.xiaojukeji.kafka.manager.common.utils; import org.springframework.util.StringUtils; @@ -21,11 +21,25 @@ public class ListUtils { if (!StringUtils.hasText(elem)) { continue; } - intList.add(Integer.parseInt(elem)); + intList.add(Integer.valueOf(elem)); } return intList; } + public static List string2LongList(String str) { + if (!StringUtils.hasText(str)) { + return new ArrayList<>(); + } + List longList = new ArrayList<>(); + for (String elem :str.split(REGEX)) { + if (!StringUtils.hasText(elem)) { + continue; + } + longList.add(Long.valueOf(elem)); + } + return longList; + } + public static List string2StrList(String str) { if (!StringUtils.hasText(str)) { return new ArrayList<>(); diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/NetUtils.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/NetUtils.java new file mode 100644 index 00000000..696c5cb8 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/NetUtils.java @@ -0,0 +1,69 @@ +package com.xiaojukeji.kafka.manager.common.utils; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; + +/** + * @author zengqiao + * @date 20/6/8 + */ +public class NetUtils { + private static String ipCache = null; + private static String hostnameCache = null; + + public static String localIp() { + if (!ValidateUtils.isBlank(ipCache)) { + return ipCache; + } + + InetAddress inetAddress = getInetAddress(); + hostnameCache = inetAddress.getHostName(); + ipCache = inetAddress.getHostAddress(); + return ipCache; + } + + public static String localHostname() { + if (!ValidateUtils.isNull(hostnameCache)) { + return hostnameCache; + } + localIp(); + return hostnameCache; + } + + public static Boolean hostnameLegal(String hostname) { + if (ValidateUtils.isExistBlank(hostname)) { + return false; + } + + hostname = hostname.trim(); + try { + InetAddress.getByName(hostname); + } catch (Exception e) { + return false; + } + return true; + } + + private static InetAddress getInetAddress() { + try { + Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces(); + while (allNetInterfaces.hasMoreElements()) { + NetworkInterface netInterface = allNetInterfaces.nextElement(); + Enumeration addresses = netInterface.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress ip = addresses.nextElement(); + if (ip != null + && ip instanceof Inet4Address + && !ip.isLoopbackAddress() //loopback地址即本机地址,IPv4的loopback范围是127.0.0.0 ~ 127.255.255.255 + && ip.getHostAddress().indexOf(":") == -1) { + return ip; + } + } + } + } catch (Exception e) { + } + return null; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/NumberUtils.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/NumberUtils.java new file mode 100644 index 00000000..56e71148 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/NumberUtils.java @@ -0,0 +1,30 @@ +package com.xiaojukeji.kafka.manager.common.utils; + +/** + * @author zhongyuankai + * @date 2020/6/8 + */ +public class NumberUtils { + + public static Long string2Long(String s) { + if (ValidateUtils.isNull(s)) { + return null; + } + try { + return Long.parseLong(s); + } catch (Exception e) { + } + return null; + } + + public static Integer string2Integer(String s) { + if (ValidateUtils.isNull(s)) { + return null; + } + try { + return Integer.parseInt(s); + } catch (Exception e) { + } + return null; + } +} diff --git a/service/src/main/java/com/xiaojukeji/kafka/manager/service/utils/SpringContextHolder.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/SpringTool.java similarity index 52% rename from service/src/main/java/com/xiaojukeji/kafka/manager/service/utils/SpringContextHolder.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/SpringTool.java index bb597322..de0783d2 100644 --- a/service/src/main/java/com/xiaojukeji/kafka/manager/service/utils/SpringContextHolder.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/SpringTool.java @@ -1,34 +1,40 @@ -package com.xiaojukeji.kafka.manager.service.utils; +package com.xiaojukeji.kafka.manager.common.utils; +import com.xiaojukeji.kafka.manager.common.constant.Constant; +import com.xiaojukeji.kafka.manager.common.constant.LoginConstant; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; import org.springframework.context.annotation.Lazy; +import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; +import java.util.Map; /** - * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicationContext * @author huangyiminghappy@163.com * @date 2019-05-08 */ @Service @Lazy(false) -public class SpringContextHolder implements ApplicationContextAware, DisposableBean { +@Order(value = 1) +public class SpringTool implements ApplicationContextAware, DisposableBean { private static ApplicationContext applicationContext = null; - private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class); + + private static Logger logger = LoggerFactory.getLogger(SpringTool.class); /** * 去的存储在静态变量中的ApplicationContext */ - public static ApplicationContext getApplicationContext() { + private static ApplicationContext getApplicationContext() { return applicationContext; } @@ -39,13 +45,21 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB return (T) applicationContext.getBean(name); } - /** - * 从静态变量applicationContext中去的Bean,自动转型为所复制对象的类型 - */ - public static T getBean(Class requiredType) { - return (T) applicationContext.getBean(requiredType); + public static T getBean(String name, Class clazz) { + return applicationContext.getBean(name, clazz); } + public static Map getBeansOfType(Class type) throws BeansException { + return getApplicationContext().getBeansOfType(type); + } + +// /** +// * 从静态变量applicationContext中去的Bean,自动转型为所复制对象的类型 +// */ +// public static T getBean(Class requiredType) { +// return (T) applicationContext.getBean(requiredType); +// } + /** * 清除SpringContextHolder中的ApplicationContext为Null */ @@ -60,8 +74,8 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB * 实现ApplicationContextAware接口,注入Context到静态变量 */ @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - SpringContextHolder.applicationContext = applicationContext; + public void setApplicationContext(ApplicationContext context) throws BeansException { + SpringTool.applicationContext = context; } /** @@ -69,12 +83,24 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB */ @Override public void destroy() throws Exception { - SpringContextHolder.clearHolder(); + SpringTool.clearHolder(); } public static String getUserName(){ - HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + HttpServletRequest request = + ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpSession session = request.getSession(); - return (String) session.getAttribute("username"); + String username = (String) session.getAttribute(LoginConstant.SESSION_USERNAME_KEY); + if (ValidateUtils.isNull(username)) { + return Constant.DEFAULT_USER_NAME; + } + return username; + } + + /** + * 发布一个事件 + */ + public static void publish(ApplicationEvent event) { + getApplicationContext().publishEvent(event); } } diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/UUIDUtils.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/UUIDUtils.java new file mode 100644 index 00000000..5dd61199 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/UUIDUtils.java @@ -0,0 +1,13 @@ +package com.xiaojukeji.kafka.manager.common.utils; + +import java.util.UUID; + +/** + * @author zengqiao + * @date 20/9/8 + */ +public class UUIDUtils { + public static String uuid() { + return UUID.randomUUID().toString().replaceAll("-", "_"); + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/ValidateUtils.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/ValidateUtils.java new file mode 100644 index 00000000..9b202ec6 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/ValidateUtils.java @@ -0,0 +1,105 @@ +package com.xiaojukeji.kafka.manager.common.utils; + +import com.xiaojukeji.kafka.manager.common.bizenum.IDCEnum; +import com.xiaojukeji.kafka.manager.common.constant.TopicCreationConstant; +import org.apache.commons.lang.StringUtils; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author zengqiao + * @date 20/4/16 + */ +public class ValidateUtils { + /** + * 为空 + */ + public static boolean isNull(Object object) { + return object == null; + } + + /** + * 是空字符串或者空 + */ + public static boolean isBlank(String str) { + return StringUtils.isBlank(str); + } + + /** + * 存在空 + */ + public static boolean isExistBlank(String str) { + int strLen; + if (str == null || (strLen = str.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if ((Character.isWhitespace(str.charAt(i)))) { + return true; + } + } + return false; + } + + /** + * 是空字符串 + */ + public static boolean equalList(List seq1, List seq2) { + if (isNull(seq1) && isNull(seq2)) { + return true; + } else if (isNull(seq1) || isNull(seq2) || seq1.size() != seq2.size()) { + return false; + } + for (Object elem: seq1) { + if (!seq2.contains(elem)) { + return false; + } + } + return true; + } + + public static boolean isEmptyList(List seq) { + return isNull(seq) || seq.isEmpty(); + } + + public static boolean isEmptySet(Set seq) { + return isNull(seq) || seq.isEmpty(); + } + + public static boolean isEmptyMap(Map seq) { + return isNull(seq) || seq.isEmpty(); + } + + public static boolean isNullOrLessThanZero(Long value) { + return value == null || value < 0; + } + + public static boolean isNullOrLessThanZero(Integer value) { + return value == null || value < 0; + } + + public static boolean isNullOrLessThanZero(Double value) { + return value == null || value < 0; + } + + public static boolean topicNameLegal(String idc, String topicName) { + if (ValidateUtils.isNull(idc) || ValidateUtils.isNull(topicName)) { + return false; + } + + // 校验Topic的长度 + if (topicName.length() >= TopicCreationConstant.TOPIC_NAME_MAX_LENGTH) { + return false; + } + + // 校验前缀 + if (IDCEnum.CN.getIdc().equals(idc) || + (IDCEnum.US.getIdc().equals(idc) && topicName.startsWith(TopicCreationConstant.TOPIC_NAME_PREFIX_US)) || + (IDCEnum.RU.getIdc().equals(idc) && topicName.startsWith(TopicCreationConstant.TOPIC_NAME_PREFIX_RU))) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DefaultThreadFactory.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/factory/DefaultThreadFactory.java similarity index 94% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DefaultThreadFactory.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/factory/DefaultThreadFactory.java index 40299de3..bfcc824f 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/DefaultThreadFactory.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/factory/DefaultThreadFactory.java @@ -1,13 +1,13 @@ -package com.xiaojukeji.kafka.manager.common.utils; +package com.xiaojukeji.kafka.manager.common.utils.factory; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** - * Created by limeng on 2017/12/22 + * @author limeng + * @date 2017/12/22 */ public class DefaultThreadFactory implements ThreadFactory { - private static final AtomicInteger POOL_ID = new AtomicInteger(); private final AtomicInteger nextId; private final String prefix; diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/factory/KafkaConsumerFactory.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/factory/KafkaConsumerFactory.java new file mode 100644 index 00000000..68109779 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/factory/KafkaConsumerFactory.java @@ -0,0 +1,63 @@ +package com.xiaojukeji.kafka.manager.common.utils.factory; + +import com.alibaba.fastjson.JSONObject; +import com.xiaojukeji.kafka.manager.common.entity.pojo.ClusterDO; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; +import org.apache.commons.pool2.BasePooledObjectFactory; +import org.apache.commons.pool2.PooledObject; +import org.apache.commons.pool2.impl.DefaultPooledObject; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.KafkaConsumer; + +import java.util.Properties; + +/** + * KafkaConsumer工厂 + * @author zengqiao + * @date 20/8/24 + */ +public class KafkaConsumerFactory extends BasePooledObjectFactory { + private ClusterDO clusterDO; + + public KafkaConsumerFactory(ClusterDO clusterDO) { + this.clusterDO = clusterDO; + } + + @Override + public KafkaConsumer create() { + return new KafkaConsumer(createKafkaConsumerProperties(clusterDO)); + } + + @Override + public PooledObject wrap(KafkaConsumer obj) { + return new DefaultPooledObject(obj); + } + + @Override + public void destroyObject(final PooledObject p) throws Exception { + KafkaConsumer kafkaConsumer = p.getObject(); + if (ValidateUtils.isNull(kafkaConsumer)) { + return; + } + kafkaConsumer.close(); + } + + private static Properties createKafkaConsumerProperties(ClusterDO clusterDO) { + Properties properties = new Properties(); + properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, clusterDO.getBootstrapServers()); + properties.setProperty( + ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, + "org.apache.kafka.common.serialization.StringDeserializer"); + properties.setProperty( + ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, + "org.apache.kafka.common.serialization.StringDeserializer"); + properties.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, 10000); + properties.put(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, 15000); + properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false); + if (ValidateUtils.isBlank(clusterDO.getSecurityProperties())) { + return properties; + } + properties.putAll(JSONObject.parseObject(clusterDO.getSecurityProperties(), Properties.class)); + return properties; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxAttributeEnum.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxAttributeEnum.java new file mode 100644 index 00000000..2c71462e --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxAttributeEnum.java @@ -0,0 +1,52 @@ +package com.xiaojukeji.kafka.manager.common.utils.jmx; + +import java.util.Arrays; + +/** + * @author zengqiao + * @date 20/6/18 + */ +public enum JmxAttributeEnum { + RATE_ATTRIBUTE(new String[]{ + "MeanRate", + "OneMinuteRate", + "FiveMinuteRate", + "FifteenMinuteRate" + }), + PERCENTILE_ATTRIBUTE(new String[]{ + "Mean", + "50thPercentile", + "75thPercentile", + "95thPercentile", + "98thPercentile", + "99thPercentile", + "999thPercentile" + }), + VALUE_ATTRIBUTE(new String[]{ + "Value" + }), + VERSION_ATTRIBUTE(new String[]{ + "Version" + }), + ; + private String[] attribute; + + JmxAttributeEnum(String[] attribute) { + this.attribute = attribute; + } + + public String[] getAttribute() { + return attribute; + } + + public void setAttribute(String[] attribute) { + this.attribute = attribute; + } + + @Override + public String toString() { + return "JmxAttributeEnum{" + + "attribute=" + Arrays.toString(attribute) + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConnectorWrap.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConnectorWrap.java new file mode 100644 index 00000000..83665791 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConnectorWrap.java @@ -0,0 +1,137 @@ +package com.xiaojukeji.kafka.manager.common.utils.jmx; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.management.*; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * JMXConnector包装类 + * @author tukun + * @date 2015/11/9. + */ +public class JmxConnectorWrap { + private final static Logger LOGGER = LoggerFactory.getLogger(JmxConnectorWrap.class); + + private String host; + + private int port; + + private JMXConnector jmxConnector; + + private AtomicInteger atomicInteger; + + public JmxConnectorWrap(String host, int port) { + this.host = host; + this.port = port; + this.atomicInteger = new AtomicInteger(25); + } + + public boolean checkJmxConnectionAndInitIfNeed() { + if (jmxConnector != null) { + return true; + } + if (port == -1) { + return false; + } + return createJmxConnector(); + } + + public synchronized void close() { + if (jmxConnector == null) { + return; + } + try { + jmxConnector.close(); + } catch (IOException e) { + LOGGER.warn("close JmxConnector exception, host:{} port:{}.", host, port, e); + } + } + + private synchronized boolean createJmxConnector() { + if (jmxConnector != null) { + return true; + } + String jmxUrl = String.format("service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi", host, port); + try { + JMXServiceURL url = new JMXServiceURL(jmxUrl); + jmxConnector = JMXConnectorFactory.connect(url, null); + LOGGER.info("JMX connect success, host:{} port:{}.", host, port); + return true; + } catch (MalformedURLException e) { + LOGGER.error("JMX url exception, host:{} port:{} jmxUrl:{}", host, port, jmxUrl, e); + } catch (Exception e) { + LOGGER.error("JMX connect exception, host:{} port:{}.", host, port, e); + } + return false; + } + + public Object getAttribute(ObjectName name, String attribute) throws + MBeanException, + AttributeNotFoundException, + InstanceNotFoundException, + ReflectionException, + IOException { + try { + acquire(); + MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); + return mBeanServerConnection.getAttribute(name, attribute); + } finally { + atomicInteger.incrementAndGet(); + } + } + + public AttributeList getAttributes(ObjectName name, String[] attributes) throws + MBeanException, + AttributeNotFoundException, + InstanceNotFoundException, + ReflectionException, + IOException { + try { + acquire(); + MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); + return mBeanServerConnection.getAttributes(name, attributes); + } finally { + atomicInteger.incrementAndGet(); + } + } + + public Set queryNames(ObjectName name, + QueryExp query) + throws IOException { + try { + acquire(); + MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); + return mBeanServerConnection.queryNames(name, query); + } finally { + atomicInteger.incrementAndGet(); + } + } + + private void acquire() { + long now = System.currentTimeMillis(); + while (true) { + try { + if (System.currentTimeMillis() - now > 60000) { + break; + } + int num = atomicInteger.get(); + if (num <= 0) { + Thread.sleep(2); + continue; + } + if (atomicInteger.compareAndSet(num, num - 1)) { + break; + } + } catch (Exception e) { + } + } + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConstant.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConstant.java new file mode 100644 index 00000000..081bfba4 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/JmxConstant.java @@ -0,0 +1,29 @@ +package com.xiaojukeji.kafka.manager.common.utils.jmx; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author zhongyuankai + * @date 20/4/13 + */ +public class JmxConstant { + /** + * 健康分 + */ + public static final String HEALTH_SCORE = "HealthScore"; + + public static final String CREATE_TIME = "CreateTime"; + + public static final String TOPIC_NUM = "TopicNum"; + + public static final String PARTITION_NUM = "PartitionNum"; + + public static final String BROKER_NUM = "BrokerNum"; + + public static final String TOPIC = "topic"; + + public static final String APP_ID = "appId"; + + public static final String TOPIC_PARTITION_LOG_SIZE = "TopicPartitionLogSize"; +} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/Mbean.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/Mbean.java similarity index 100% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/Mbean.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/Mbean.java diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtil.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtil.java new file mode 100644 index 00000000..b62b390e --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtil.java @@ -0,0 +1,79 @@ +package com.xiaojukeji.kafka.manager.common.utils.jmx; + +import java.util.HashMap; +import java.util.Map; + +/** + * kafka集群的mbean的object name集合 + * @author tukun, zengqiao + * @date 2015/11/5. + */ +public class MbeanNameUtil { + /** + * 社区Metrics指标 + */ + + /** + * 滴滴Metrics指标 + */ + private static final String PRODUCE_BYTES_IN_PER_SEC = "kafka.server:type=DiskMetrics,name=ProducerBytesInPerSec"; + + /** + * 限流指标 + */ + private static final String PRODUCE_THROTTLE_TIME = "kafka.server:type=Produce,client-id=*"; + private static final String FETCH_THROTTLE_TIME = "kafka.server:type=Fetch,client-id=*"; + + + private static final String TOPIC_PARTITION_LOG_SIZE = "kafka.log:type=Log,name=Size,topic=%s,partition=%d"; + + + /** + * 存储监控的参数name到获取的object_name的映射关系图 + */ + private static Map MBEAN_NAME_MAP = new HashMap<>(); + static { + + MBEAN_NAME_MAP.put("ProduceThrottleTime", new Mbean(MbeanNameUtil.PRODUCE_THROTTLE_TIME, "throttle-time", Double.class)); + MBEAN_NAME_MAP.put("FetchThrottleTime", new Mbean(MbeanNameUtil.FETCH_THROTTLE_TIME, "throttle-time", Double.class)); + + + + /** + * 滴滴Metrics指标 + */ + MBEAN_NAME_MAP.put("ProducerBytesInPerSec", new Mbean(PRODUCE_BYTES_IN_PER_SEC,"OneMinuteRate", Double.class)); + + MBEAN_NAME_MAP.put("TopicPartitionLogSize", new Mbean(TOPIC_PARTITION_LOG_SIZE, "Value", Long.class)); + + } + + /** + * 根据属性名,kafka版本,topic获取相应的Mbean + */ + public static Mbean getMbean(String mbeanName) { + return MBEAN_NAME_MAP.get(mbeanName); + } + + public static Mbean getMbean(String mbeanName, String topicName) { + Mbean mbean = MBEAN_NAME_MAP.get(mbeanName); + if (mbean == null) { + return null; + } + if (topicName == null || topicName.isEmpty()) { + return mbean; + } + return new Mbean(mbean.getObjectName() + ",topic=" + topicName, mbean.getProperty(), mbean.getPropertyClass()); + } + + public static Mbean getMbean(String mbeanName, Integer brokerId) { + Mbean mbean = MBEAN_NAME_MAP.get(mbeanName); + if (mbean == null) { + return null; + } + if (brokerId == null) { + return mbean; + } + return new Mbean(mbean.getObjectName() + ",id=" + brokerId, mbean.getProperty(), mbean.getPropertyClass()); + } +} diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtilV2.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtilV2.java new file mode 100644 index 00000000..d7d4ffe9 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanNameUtilV2.java @@ -0,0 +1,445 @@ +package com.xiaojukeji.kafka.manager.common.utils.jmx; + +import com.xiaojukeji.kafka.manager.common.constant.KafkaMetricsCollections; +import com.xiaojukeji.kafka.manager.common.entity.KafkaVersion; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; + +import java.util.*; + +/** + * kafka集群的mbean的object name集合 + * @author zengqiao + * @date 20/6/15 + */ +public class MbeanNameUtilV2 { + + private static Map> FIELD_NAME_MBEAN_MAP = new HashMap<>(); + + private static void initMbean(MbeanV2 mbeanV2, List interfaceIdList) { + for (Integer interfaceId: interfaceIdList) { + List mbeanV2List = FIELD_NAME_MBEAN_MAP.getOrDefault(interfaceId, new ArrayList<>()); + mbeanV2List.add(mbeanV2); + FIELD_NAME_MBEAN_MAP.put(interfaceId, mbeanV2List); + } + } + + static { + //社区Kafka指标------------------------------------------------------------------------------------------- + + for (String fieldName: Arrays.asList("BytesInPerSec", "BytesOutPerSec")) { + initMbean( + new MbeanV2( + fieldName, + JmxAttributeEnum.RATE_ATTRIBUTE, + "kafka.server:type=BrokerTopicMetrics,name=" + fieldName + ), + Arrays.asList( + KafkaMetricsCollections.COMMON_DETAIL_METRICS, + KafkaMetricsCollections.BROKER_OVERVIEW_PAGE_METRICS, + KafkaMetricsCollections.TOPIC_METRICS_TO_DB, + KafkaMetricsCollections.BROKER_TO_DB_METRICS, + KafkaMetricsCollections.BROKER_ANALYSIS_METRICS, + KafkaMetricsCollections.BROKER_TOPIC_ANALYSIS_METRICS + ) + ); + } + + for (String fieldName: Arrays.asList( + "MessagesInPerSec", + "BytesRejectedPerSec", + "TotalProduceRequestsPerSec", + "TotalFetchRequestsPerSec" + )) { + initMbean( + new MbeanV2( + fieldName, + JmxAttributeEnum.RATE_ATTRIBUTE, + "kafka.server:type=BrokerTopicMetrics,name=" + fieldName + ), + Arrays.asList( + KafkaMetricsCollections.COMMON_DETAIL_METRICS, + KafkaMetricsCollections.TOPIC_METRICS_TO_DB, + KafkaMetricsCollections.BROKER_TO_DB_METRICS, + KafkaMetricsCollections.BROKER_ANALYSIS_METRICS, + KafkaMetricsCollections.BROKER_TOPIC_ANALYSIS_METRICS + ) + ); + } + + for (String fieldName: Arrays.asList( + "FailedFetchRequestsPerSec", + "FailedProduceRequestsPerSec" + )) { + initMbean( + new MbeanV2( + fieldName, + JmxAttributeEnum.RATE_ATTRIBUTE, + "kafka.server:type=BrokerTopicMetrics,name=" + fieldName + ), + Arrays.asList( + KafkaMetricsCollections.COMMON_DETAIL_METRICS, + KafkaMetricsCollections.TOPIC_METRICS_TO_DB, + KafkaMetricsCollections.BROKER_TO_DB_METRICS, + KafkaMetricsCollections.BROKER_ANALYSIS_METRICS, + KafkaMetricsCollections.BROKER_TOPIC_ANALYSIS_METRICS, + KafkaMetricsCollections.BROKER_HEALTH_SCORE_METRICS + + ) + ); + } + + for (String fieldName: Arrays.asList("Produce", "FetchConsumer")) { + initMbean( + new MbeanV2( + fieldName + "RequestsPerSec", + JmxAttributeEnum.RATE_ATTRIBUTE, + "kafka.network:type=RequestMetrics,name=RequestsPerSec,request=" + fieldName + ), + Arrays.asList( + KafkaMetricsCollections.BROKER_TO_DB_METRICS + ) + ); + } + + initMbean( + new MbeanV2( + "RequestHandlerAvgIdlePercent", + JmxAttributeEnum.RATE_ATTRIBUTE, + "kafka.server:type=KafkaRequestHandlerPool,name=RequestHandlerAvgIdlePercent" + ), + Arrays.asList( + KafkaMetricsCollections.BROKER_TO_DB_METRICS, + KafkaMetricsCollections.BROKER_HEALTH_SCORE_METRICS + ) + ); + + initMbean( + new MbeanV2( + "NetworkProcessorAvgIdlePercent", + JmxAttributeEnum.VALUE_ATTRIBUTE, + "kafka.network:type=SocketServer,name=NetworkProcessorAvgIdlePercent" + ), + Arrays.asList( + KafkaMetricsCollections.BROKER_TO_DB_METRICS, + KafkaMetricsCollections.BROKER_HEALTH_SCORE_METRICS + ) + ); + + for (String fieldName: Arrays.asList("RequestQueueSize", "ResponseQueueSize")) { + initMbean( + new MbeanV2( + fieldName, + JmxAttributeEnum.VALUE_ATTRIBUTE, + "kafka.network:type=RequestChannel,name=" + fieldName + ), + Arrays.asList( + KafkaMetricsCollections.BROKER_TO_DB_METRICS, KafkaMetricsCollections.BROKER_HEALTH_SCORE_METRICS + ) + ); + } + + for (String fieldName: Arrays.asList("Produce", "FetchConsumer")) { + initMbean( + new MbeanV2( + fieldName + "TotalTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + "kafka.network:type=RequestMetrics,name=TotalTimeMs,request=" + fieldName + ), + Arrays.asList( + KafkaMetricsCollections.BROKER_TO_DB_METRICS + ) + ); + } + + for (String fieldName: Arrays.asList("PartitionCount", "LeaderCount", "UnderReplicatedPartitions")) { + initMbean( + new MbeanV2( + fieldName, + JmxAttributeEnum.VALUE_ATTRIBUTE, + "kafka.server:type=ReplicaManager,name=" + fieldName + ), + Arrays.asList( + KafkaMetricsCollections.BROKER_BASIC_PAGE_METRICS, + KafkaMetricsCollections.BROKER_OVERVIEW_PAGE_METRICS, + KafkaMetricsCollections.BROKER_STATUS_PAGE_METRICS + ) + ); + } + + initMbean( + new MbeanV2( + "TopicCodeC", + JmxAttributeEnum.VALUE_ATTRIBUTE, + "kafka.server:type=ReplicaManager,name=TopicCodeC" + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_BASIC_PAGE_METRICS + ) + ); + + + + + initMbean( + new MbeanV2( + "LogFlushRateAndTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + "kafka.log:type=LogFlushStats,name=LogFlushRateAndTimeMs" + ), + Arrays.asList( + KafkaMetricsCollections.BROKER_TO_DB_METRICS + ) + ); + + initMbean( + new MbeanV2( + "LogEndOffset", + JmxAttributeEnum.VALUE_ATTRIBUTE, + "kafka.log:type=Log,name=LogEndOffset" + ), + Arrays.asList( + ) + ); + + for (String fieldName: Arrays.asList("Produce")) { + initMbean(new MbeanV2( + fieldName + "TotalTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=TotalTimeMs,request=" + fieldName), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=TotalTimeMs,request=" + fieldName) + ) + + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_METRICS_TO_DB, + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "RequestQueueTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=RequestQueueTimeMs,request=" + fieldName), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=RequestQueueTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "LocalTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=LocalTimeMs,request=" + fieldName), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=LocalTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "RemoteTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=RemoteTimeMs,request=" + fieldName), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=RemoteTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "ThrottleTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=ThrottleTimeMs,request=" + fieldName), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=ThrottleTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "ResponseQueueTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=ResponseQueueTimeMs,request=" + fieldName), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=ResponseQueueTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "ResponseSendTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=ResponseSendTimeMs,request=" + fieldName), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=ResponseSendTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + } + + for (String fieldName: Arrays.asList("Fetch")) { + initMbean(new MbeanV2( + fieldName + "ConsumerTotalTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=TotalTimeMs,request=" + fieldName + "Consumer"), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=TotalTimeMs,request=" + fieldName) + ) + + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_METRICS_TO_DB, + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "ConsumerRequestQueueTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=RequestQueueTimeMs,request=" + fieldName + "Consumer"), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=RequestQueueTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "ConsumerLocalTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=LocalTimeMs,request=" + fieldName + "Consumer"), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=LocalTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "ConsumerRemoteTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=RemoteTimeMs,request=" + fieldName + "Consumer"), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=RemoteTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "ConsumerThrottleTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=ThrottleTimeMs,request=" + fieldName + "Consumer"), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=ThrottleTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "ConsumerResponseQueueTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=ResponseQueueTimeMs,request=" + fieldName + "Consumer"), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=ResponseQueueTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + + initMbean( + new MbeanV2( + fieldName + "ConsumerResponseSendTimeMs", + JmxAttributeEnum.PERCENTILE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.network:type=TopicRequestMetrics,name=ResponseSendTimeMs,request=" + fieldName + "Consumer"), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=TopicRequestMetrics,name=ResponseSendTimeMs,request=" + fieldName) + ) + ), + Arrays.asList( + KafkaMetricsCollections.TOPIC_REQUEST_TIME_DETAIL_PAGE_METRICS + ) + ); + } + + initMbean( + new MbeanV2( + "KafkaVersion", + JmxAttributeEnum.VERSION_ATTRIBUTE, + "kafka.server:type=app-info" + ), + Arrays.asList( + KafkaMetricsCollections.BROKER_VERSION + ) + ); + + + //滴滴Kafka指标------------------------------------------------------------------------------------------- + for (String fieldName: Arrays.asList("AppIdBytesInPerSec", "AppIdBytesOutPerSec", "AppIdMessagesInPerSec")) { + initMbean( + new MbeanV2( + "Topic" + fieldName, + JmxAttributeEnum.RATE_ATTRIBUTE, + Arrays.asList( + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.server:type=AppIdTopicMetrics,name=" + fieldName + ",topic=*,appId=*"), + new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=AppIdTopicMetrics,name=" + fieldName.replace("AppId", "") + ",topic=*,appId=*") + ) + ), + Arrays.asList( + KafkaMetricsCollections.APP_TOPIC_METRICS_TO_DB + ) + ); + } + }; + + /** + * 根据属性名,kafka版本,topic获取相应的Mbean + */ + public static List getMbeanList(Integer interfaceId) { + if (ValidateUtils.isNull(interfaceId)) { + return new ArrayList<>(); + } + return FIELD_NAME_MBEAN_MAP.getOrDefault(interfaceId, new ArrayList<>()); + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanV2.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanV2.java new file mode 100644 index 00000000..e8baaa0b --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/jmx/MbeanV2.java @@ -0,0 +1,69 @@ +package com.xiaojukeji.kafka.manager.common.utils.jmx; + +import com.xiaojukeji.kafka.manager.common.entity.KafkaVersion; +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; + +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * @author zengqiao + * @date 20/6/15 + */ +public class MbeanV2 { + private String fieldName; + + /** + * mbean对象被监控的属性名称 + */ + private JmxAttributeEnum attributeEnum; + + /** + * mbean的对象名称 + */ + private Map versionObjectNameMap = new TreeMap<>(); + + public MbeanV2(String fieldName, JmxAttributeEnum attributeEnum, String objectName) { + this.fieldName = fieldName; + this.attributeEnum = attributeEnum; + this.versionObjectNameMap.put(KafkaVersion.VERSION_MAX, objectName); + } + + public MbeanV2(String fieldName, JmxAttributeEnum attributeEnum, List> versionObjectNames) { + this.fieldName = fieldName; + this.attributeEnum = attributeEnum; + for (Map.Entry entry: versionObjectNames) { + this.versionObjectNameMap.put(entry.getKey(), entry.getValue()); + } + } + + public String getFieldName() { + return fieldName; + } + + public JmxAttributeEnum getAttributeEnum() { + return attributeEnum; + } + + public String getObjectName(Long versionNum) { + if (ValidateUtils.isNull(versionNum)) { + return versionObjectNameMap.get(KafkaVersion.VERSION_MAX); + } + for (Map.Entry entry: versionObjectNameMap.entrySet()) { + if (entry.getKey() >= versionNum) { + return entry.getValue(); + } + } + return null; + } + + @Override + public String toString() { + return "MbeanV2{" + + "fieldName='" + fieldName + '\'' + + ", attributeEnum=" + attributeEnum + + ", versionObjectNameMap=" + versionObjectNameMap + + '}'; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/ConfigClient.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/ConfigClient.java similarity index 98% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/ConfigClient.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/ConfigClient.java index 0986cc75..ca155a79 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/ConfigClient.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/ConfigClient.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.utils.zk; +package com.xiaojukeji.kafka.manager.common.zookeeper; import com.xiaojukeji.kafka.manager.common.exception.ConfigException; import org.apache.zookeeper.data.Stat; diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/StateChangeListener.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/StateChangeListener.java new file mode 100644 index 00000000..f4dea218 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/StateChangeListener.java @@ -0,0 +1,22 @@ +package com.xiaojukeji.kafka.manager.common.zookeeper; + +/** + * @author limeng + * @date 2017/12/22 + */ +public interface StateChangeListener { + enum State { + CONNECTION_RECONNECT, // + CONNECTION_DISCONNECT, + NODE_DATA_CHANGED, + CHILD_UPDATED, + CHILD_ADDED, + CHILD_DELETED, + // + ; + } + + void init(); + + void onChange(State state, String path); +} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/ZkConfigImpl.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/ZkConfigImpl.java similarity index 99% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/ZkConfigImpl.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/ZkConfigImpl.java index 3ca37639..d41bc7d5 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/utils/zk/ZkConfigImpl.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/ZkConfigImpl.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.utils.zk; +package com.xiaojukeji.kafka.manager.common.zookeeper; import com.alibaba.fastjson.JSON; import com.xiaojukeji.kafka.manager.common.exception.ConfigException; @@ -23,7 +23,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/ZkPathUtil.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/ZkPathUtil.java new file mode 100644 index 00000000..b1758205 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/ZkPathUtil.java @@ -0,0 +1,114 @@ +package com.xiaojukeji.kafka.manager.common.zookeeper; + +/** + * @author tukun + * @date 15/11/05 + * @version 1.0.0 + */ +public class ZkPathUtil { + private static final String ZOOKEEPER_SEPARATOR = "/"; + + private static final String BROKER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "brokers"; + + public static final String CONTROLLER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "controller"; + + public static final String BROKER_IDS_ROOT = BROKER_ROOT_NODE + ZOOKEEPER_SEPARATOR + "ids"; + + public static final String BROKER_TOPICS_ROOT = BROKER_ROOT_NODE + ZOOKEEPER_SEPARATOR + "topics"; + + public static final String CONSUMER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "consumers"; + + /** + * config + */ + public static final String CONFIG_ROOT_NODE = ZOOKEEPER_SEPARATOR + "config"; + + public static final String CONFIG_TOPICS_ROOT_NODE = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "topics"; + + public static final String CONFIG_CLIENTS_ROOT_NODE = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "clients"; + + public static final String CONFIG_ENTITY_CHANGES_ROOT_NODE = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "changes/config_change_"; + + public static final String REASSIGN_PARTITIONS_ROOT_NODE = "/admin/reassign_partitions"; + + private static final String D_METRICS_CONFIG_ROOT_NODE = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "KafkaExMetrics"; + + public static String getBrokerIdNodePath(Integer brokerId) { + return BROKER_IDS_ROOT + ZOOKEEPER_SEPARATOR + String.valueOf(brokerId); + } + + public static String getBrokerTopicRoot(String topicName) { + return BROKER_TOPICS_ROOT + ZOOKEEPER_SEPARATOR + topicName; + } + + public static String getBrokerTopicPartitionStatePath(String topicName, Integer partitionId) { + return BROKER_TOPICS_ROOT + ZOOKEEPER_SEPARATOR + topicName + ZOOKEEPER_SEPARATOR + "partitions" + + ZOOKEEPER_SEPARATOR + String.valueOf(partitionId) + ZOOKEEPER_SEPARATOR + "state"; + } + + //for consumer + public static String getConsumerTopicPartitionOffsetNodePath(String consumerGroup, + String topic, int partitionId) { + return String.format(CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR + "%s" + ZOOKEEPER_SEPARATOR + + "offset" + "%s" + "%d", consumerGroup, topic, partitionId); + } + + public static String getConsumerGroupRoot(String consumerGroup) { + return CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR + consumerGroup; + } + + public static String getConsumerGroupIdsRoot(String consumerGroup) { + return CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR + consumerGroup + ZOOKEEPER_SEPARATOR + + "ids"; + } + + public static String getConsumerGroupOffsetRoot(String consumerGroup) { + return CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR + consumerGroup + ZOOKEEPER_SEPARATOR + + "offsets"; + } + + public static String getConsumerGroupOwnersRoot(String consumerGroup) { + return CONSUMER_ROOT_NODE + ZOOKEEPER_SEPARATOR + consumerGroup + ZOOKEEPER_SEPARATOR + + "owners"; + } + + public static String getConsumerGroupConsumerIdsNodePath(String consumerGroup, String consumerId) { + return getConsumerGroupIdsRoot(consumerGroup) + ZOOKEEPER_SEPARATOR + consumerId; + } + + public static String getConsumerGroupOffsetTopicNode(String consumerGroup, String topic) { + return getConsumerGroupOffsetRoot(consumerGroup) + ZOOKEEPER_SEPARATOR + topic; + } + + public static String getConsumerGroupOffsetTopicPartitionNode(String consumerGroup, + String topic, int partitionId) { + return getConsumerGroupOffsetTopicNode(consumerGroup, topic) + ZOOKEEPER_SEPARATOR + + partitionId; + } + + public static String getConsumerGroupOwnersTopicNode(String consumerGroup, String topic) { + return getConsumerGroupOwnersRoot(consumerGroup) + ZOOKEEPER_SEPARATOR + topic; + } + + public static String getConsumerGroupOwnersTopicPartitionNode(String consumerGroup, + String topic, int partitionId) { + return getConsumerGroupOwnersTopicNode(consumerGroup, topic) + ZOOKEEPER_SEPARATOR + + partitionId; + } + + public static String getConfigTopicNode(String topicName) { + return CONFIG_TOPICS_ROOT_NODE + ZOOKEEPER_SEPARATOR + topicName; + } + + public static String getConfigClientNodePath(String appId, String topicName) { + return CONFIG_CLIENTS_ROOT_NODE + ZOOKEEPER_SEPARATOR + appId + "." + topicName; + } + + public static String parseLastPartFromZkPath(String zkPath) { + return zkPath.substring(zkPath.lastIndexOf(ZOOKEEPER_SEPARATOR) + 1); + } + + public static String getKafkaExtraMetricsPath(Integer brokerId) { + return D_METRICS_CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + String.valueOf(brokerId); + } +} diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ControllerData.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ControllerData.java similarity index 93% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ControllerData.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ControllerData.java index aed4f1e8..f5ea25ce 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ControllerData.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ControllerData.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.zookeeper; +package com.xiaojukeji.kafka.manager.common.zookeeper.znode; /** * @author zengqiao diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentDTO.java similarity index 94% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentDTO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentDTO.java index c58ea9da..0cfc29d4 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentDTO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentDTO.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.zookeeper; +package com.xiaojukeji.kafka.manager.common.zookeeper.znode; import java.util.ArrayList; import java.util.HashMap; diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentElemDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentElemData.java similarity index 90% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentElemDTO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentElemData.java index 8c886d58..0480e88a 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentElemDTO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentElemData.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.zookeeper; +package com.xiaojukeji.kafka.manager.common.zookeeper.znode; import java.util.List; @@ -6,7 +6,7 @@ import java.util.List; * @author zengqiao * @date 20/1/15 */ -public class ReassignmentElemDTO { +public class ReassignmentElemData { private String topic; private Integer partition; diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentJsonDTO.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentJsonData.java similarity index 65% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentJsonDTO.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentJsonData.java index abf5d94b..45c5b9e6 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/ReassignmentJsonDTO.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/ReassignmentJsonData.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.zookeeper; +package com.xiaojukeji.kafka.manager.common.zookeeper.znode; import java.util.List; @@ -6,10 +6,10 @@ import java.util.List; * @author zengqiao * @date 20/1/15 */ -public class ReassignmentJsonDTO { +public class ReassignmentJsonData { private Integer version; - private List partitions; + private List partitions; public Integer getVersion() { return version; @@ -19,11 +19,11 @@ public class ReassignmentJsonDTO { this.version = version; } - public List getPartitions() { + public List getPartitions() { return partitions; } - public void setPartitions(List partitions) { + public void setPartitions(List partitions) { this.partitions = partitions; } diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/BrokerMetadata.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/BrokerMetadata.java similarity index 94% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/BrokerMetadata.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/BrokerMetadata.java index e6ab28e8..51c4b06b 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/BrokerMetadata.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/BrokerMetadata.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.zookeeper; +package com.xiaojukeji.kafka.manager.common.zookeeper.znode.brokers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,7 +34,9 @@ public class BrokerMetadata implements Cloneable { private int port; - //zk上字段对应 + /* + * ZK上对应的字段就是这个名字, 不要进行修改 + */ private int jmx_port; private String version; diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/PartitionMap.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/PartitionMap.java similarity index 80% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/PartitionMap.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/PartitionMap.java index 77fed464..48bf2129 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/PartitionMap.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/PartitionMap.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.zookeeper; +package com.xiaojukeji.kafka.manager.common.zookeeper.znode.brokers; import java.io.Serializable; import java.util.List; @@ -39,6 +39,9 @@ public class PartitionMap implements Serializable { @Override public String toString() { - return "PartitionMap{" + "version=" + version + ", partitions=" + partitions + '}'; + return "PartitionMap{" + + "version=" + version + + ", partitions=" + partitions + + '}'; } } diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/PartitionState.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/PartitionState.java similarity index 96% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/PartitionState.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/PartitionState.java index 95e8c522..ade9680b 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/PartitionState.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/PartitionState.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.zookeeper; +package com.xiaojukeji.kafka.manager.common.zookeeper.znode.brokers; import java.util.ArrayList; import java.util.List; @@ -41,7 +41,7 @@ public class PartitionState implements Cloneable { private List isr; /** - * 是否处于复制同步状态 + * 是否处于复制同步状态, true表示未同步, false表示已经同步 */ private boolean isUnderReplicated; diff --git a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/TopicMetadata.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/TopicMetadata.java similarity index 96% rename from common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/TopicMetadata.java rename to kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/TopicMetadata.java index fc15eada..928276cf 100644 --- a/common/src/main/java/com/xiaojukeji/kafka/manager/common/entity/zookeeper/TopicMetadata.java +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/brokers/TopicMetadata.java @@ -1,4 +1,4 @@ -package com.xiaojukeji.kafka.manager.common.entity.zookeeper; +package com.xiaojukeji.kafka.manager.common.zookeeper.znode.brokers; import java.util.Set; diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/ChangeData.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/ChangeData.java new file mode 100644 index 00000000..20ed2f04 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/ChangeData.java @@ -0,0 +1,44 @@ +package com.xiaojukeji.kafka.manager.common.zookeeper.znode.config; + +/** + * @author zengqiao + * @date 20/5/14 + */ +public class ChangeData { + private static final Integer CHANGE_DATA_VERSION = 2; + + private String entity_path; + + private Integer version; + + public String getEntity_path() { + return entity_path; + } + + public void setEntity_path(String entity_path) { + this.entity_path = entity_path; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public static ChangeData getChangeData(String entity_path) { + ChangeData changeData = new ChangeData(); + changeData.setEntity_path(entity_path); + changeData.setVersion(CHANGE_DATA_VERSION); + return changeData; + } + + @Override + public String toString() { + return "ConfigChangesData{" + + "entity_path='" + entity_path + '\'' + + ", version=" + version + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/ConfigNodeData.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/ConfigNodeData.java new file mode 100644 index 00000000..97bf3fa7 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/ConfigNodeData.java @@ -0,0 +1,37 @@ +package com.xiaojukeji.kafka.manager.common.zookeeper.znode.config; + +/** + * @author zengqiao + * @date 20/5/12 + */ +public class ConfigNodeData { + public static final Integer CONFIGDATA_VERSION = 1; + + private T config; + + private Integer version; + + public T getConfig() { + return config; + } + + public void setConfig(T config) { + this.config = config; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + @Override + public String toString() { + return "CommonDataDTO{" + + "config=" + config + + ", version=" + version + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/TopicQuotaData.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/TopicQuotaData.java new file mode 100644 index 00000000..99eb3051 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/config/TopicQuotaData.java @@ -0,0 +1,48 @@ +package com.xiaojukeji.kafka.manager.common.zookeeper.znode.config; + +import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils; + +/** + * @author zengqiao + * @date 20/5/12 + */ +public class TopicQuotaData { + private String consumer_byte_rate; + + private String producer_byte_rate; + + public String getConsumer_byte_rate() { + return consumer_byte_rate; + } + + public void setConsumer_byte_rate(String consumer_byte_rate) { + this.consumer_byte_rate = consumer_byte_rate; + } + + public String getProducer_byte_rate() { + return producer_byte_rate; + } + + public void setProducer_byte_rate(String producer_byte_rate) { + this.producer_byte_rate = producer_byte_rate; + } + + public static TopicQuotaData getClientData(Long producerByteRate, Long consumerByteRate) { + TopicQuotaData clientData = new TopicQuotaData(); + if (!ValidateUtils.isNull(producerByteRate) && consumerByteRate != -1) { + clientData.setConsumer_byte_rate(consumerByteRate.toString()); + } + if (!ValidateUtils.isNull(consumerByteRate) && producerByteRate != -1) { + clientData.setProducer_byte_rate(producerByteRate.toString()); + } + return clientData; + } + + @Override + public String toString() { + return "ClientQuotaData{" + + "consumer_byte_rate='" + consumer_byte_rate + '\'' + + ", producer_byte_rate='" + producer_byte_rate + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/didi/JmxSwitchDataConstant.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/didi/JmxSwitchDataConstant.java new file mode 100644 index 00000000..134979e2 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/didi/JmxSwitchDataConstant.java @@ -0,0 +1,15 @@ +package com.xiaojukeji.kafka.manager.common.zookeeper.znode.didi; + +/** + * @author zengqiao + * @date 20/8/21 + */ +public class JmxSwitchDataConstant { + public static final String TOPIC_REQUEST_METRICS = "TopicRequestMetrics."; + + public static final String APP_ID_TOPIC_METRICS = "AppIdTopicMetrics."; + + public static final String CLIENT_REQUEST_METRICS = "ClientRequestMetrics."; + + public static final String DISK_METRICS = "DiskMetrics."; +} \ No newline at end of file diff --git a/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/didi/TopicJmxSwitch.java b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/didi/TopicJmxSwitch.java new file mode 100644 index 00000000..b43904a9 --- /dev/null +++ b/kafka-manager-common/src/main/java/com/xiaojukeji/kafka/manager/common/zookeeper/znode/didi/TopicJmxSwitch.java @@ -0,0 +1,54 @@ +package com.xiaojukeji.kafka.manager.common.zookeeper.znode.didi; + +/** + * @author zengqiao + * @date 20/8/21 + */ +public class TopicJmxSwitch { + private Boolean openTopicRequestMetrics = Boolean.FALSE; + + private Boolean openAppIdTopicMetrics = Boolean.FALSE; + + private Boolean openClientRequestMetrics = Boolean.FALSE; + + public TopicJmxSwitch(Boolean openTopicRequestMetrics, + Boolean openAppIdTopicMetrics, + Boolean openClientRequestMetrics) { + this.openTopicRequestMetrics = openTopicRequestMetrics; + this.openAppIdTopicMetrics = openAppIdTopicMetrics; + this.openClientRequestMetrics = openClientRequestMetrics; + } + + public Boolean getOpenTopicRequestMetrics() { + return openTopicRequestMetrics; + } + + public void setOpenTopicRequestMetrics(Boolean openTopicRequestMetrics) { + this.openTopicRequestMetrics = openTopicRequestMetrics; + } + + public Boolean getOpenAppIdTopicMetrics() { + return openAppIdTopicMetrics; + } + + public void setOpenAppIdTopicMetrics(Boolean openAppIdTopicMetrics) { + this.openAppIdTopicMetrics = openAppIdTopicMetrics; + } + + public Boolean getOpenClientRequestMetrics() { + return openClientRequestMetrics; + } + + public void setOpenClientRequestMetrics(Boolean openClientRequestMetrics) { + this.openClientRequestMetrics = openClientRequestMetrics; + } + + @Override + public String toString() { + return "TopicJmxSwitch{" + + "openTopicRequestMetrics=" + openTopicRequestMetrics + + ", openAppIdTopicMetrics=" + openAppIdTopicMetrics + + ", openClientRequestMetrics=" + openClientRequestMetrics + + '}'; + } +} \ No newline at end of file diff --git a/console/package.json b/kafka-manager-console/package.json similarity index 80% rename from console/package.json rename to kafka-manager-console/package.json index 121533c0..b823bf3d 100644 --- a/console/package.json +++ b/kafka-manager-console/package.json @@ -12,15 +12,19 @@ "license": "ISC", "devDependencies": { "@hot-loader/react-dom": "^16.8.6", - "@types/echarts": "^4.1.9", + "@types/clipboard": "^2.0.1", + "@types/echarts": "^4.4.1", + "@types/lodash.debounce": "^4.0.6", "@types/react": "^16.8.8", "@types/react-dom": "^16.8.2", "@types/react-router-dom": "^4.3.1", - "antd": "^3.16.1", + "@types/spark-md5": "^3.0.2", + "antd": "^3.26.15", "clean-webpack-plugin": "^3.0.0", + "clipboard": "^2.0.6", "cross-env": "^7.0.2", "css-loader": "^2.1.0", - "echarts": "^4.2.1", + "echarts": "^4.5.0", "file-loader": "^5.0.2", "html-webpack-plugin": "^3.2.0", "less": "^3.9.0", @@ -33,6 +37,7 @@ "react": "^16.8.4", "react-hot-loader": "^4.8.4", "react-router-dom": "^5.0.0", + "spark-md5": "^3.0.1", "style-loader": "^0.23.1", "terser-webpack-plugin": "^1.2.3", "ts-loader": "^5.3.3", @@ -42,6 +47,7 @@ "typescript": "^3.3.3333", "webpack": "^4.29.6", "webpack-cli": "^3.2.3", - "webpack-dev-server": "^3.2.1" + "webpack-dev-server": "^3.2.1", + "xlsx": "^0.16.1" } } diff --git a/console/pom.xml b/kafka-manager-console/pom.xml similarity index 97% rename from console/pom.xml rename to kafka-manager-console/pom.xml index 40a10973..86adec26 100644 --- a/console/pom.xml +++ b/kafka-manager-console/pom.xml @@ -5,7 +5,7 @@ kafka-manager com.xiaojukeji.kafka - 1.1.0-SNAPSHOT + 1.0.0-SNAPSHOT 4.0.0 kafka-manager-console @@ -53,4 +53,4 @@ - \ No newline at end of file + diff --git a/console/src/assets/image/admin.png b/kafka-manager-console/src/assets/image/admin.png similarity index 100% rename from console/src/assets/image/admin.png rename to kafka-manager-console/src/assets/image/admin.png diff --git a/console/src/assets/image/devops.png b/kafka-manager-console/src/assets/image/devops.png similarity index 100% rename from console/src/assets/image/devops.png rename to kafka-manager-console/src/assets/image/devops.png diff --git a/console/src/assets/image/images.d.ts b/kafka-manager-console/src/assets/image/images.d.ts similarity index 100% rename from console/src/assets/image/images.d.ts rename to kafka-manager-console/src/assets/image/images.d.ts diff --git a/console/src/assets/image/kafka-logo.png b/kafka-manager-console/src/assets/image/kafka-logo.png similarity index 100% rename from console/src/assets/image/kafka-logo.png rename to kafka-manager-console/src/assets/image/kafka-logo.png diff --git a/console/src/assets/image/kafka-manager.png b/kafka-manager-console/src/assets/image/kafka-manager.png similarity index 100% rename from console/src/assets/image/kafka-manager.png rename to kafka-manager-console/src/assets/image/kafka-manager.png diff --git a/console/src/assets/image/login-bg.png b/kafka-manager-console/src/assets/image/login-bg.png similarity index 100% rename from console/src/assets/image/login-bg.png rename to kafka-manager-console/src/assets/image/login-bg.png diff --git a/console/src/assets/image/logo.ico b/kafka-manager-console/src/assets/image/logo.ico similarity index 100% rename from console/src/assets/image/logo.ico rename to kafka-manager-console/src/assets/image/logo.ico diff --git a/console/src/assets/image/normal.png b/kafka-manager-console/src/assets/image/normal.png similarity index 100% rename from console/src/assets/image/normal.png rename to kafka-manager-console/src/assets/image/normal.png diff --git a/kafka-manager-console/src/assets/image/wechat.jpeg b/kafka-manager-console/src/assets/image/wechat.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..6333ad89960e3a1d2d0290cc934670b411f86bbd GIT binary patch literal 128319 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 Y55~#7E`$q7u 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

    _J^8R&X^u9Z{w9hn|r@K9NWt;dbzzF~SKhWL! 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 { + public id: HTMLDivElement = null; + public chart: echarts.ECharts; + + public state = { + loading: false, + noData: false, + }; + + public componentDidMount() { + this.chart = echarts.init(this.id); + this.getChartData(); + window.addEventListener('resize', this.resize); + } + + public componentWillUnmount() { + window.removeEventListener('resize', this.resize); + } + + public resize = () => { + this.chart.resize(); + } + + public isHasData = (data: EChartOption) => { + const noData = !(data.series && data.series.length); + this.setState({ noData }); + return !noData; + } + + public getChartData = () => { + const { getChartData } = this.props; + if (!getChartData) { + return notification.error({ message: '图表信息有误' }); + } + + this.setState({ loading: true }); + const chartOptions = getChartData(); + + if ((typeof chartOptions.then) === 'function') { + return chartOptions.then((data: EChartOption) => { + this.setState({ loading: false }); + + if (this.isHasData(data)) { + this.changeChartOptions(data); + } + }); + } + + if (this.isHasData(chartOptions)) { + this.changeChartOptions(chartOptions); + this.setState({ loading: false }); + } + } + + public changeChartOptions(options: any) { + this.chart.setOption(options, true); + } + + public handleRefreshChart() { + this.getChartData(); + } + + public render() { + return ( + <> + + {this.state.noData ?

    暂无数据
    : null} +
    this.id = id} /> + + + ); + } +} diff --git a/kafka-manager-console/src/component/chart/date-picker-chart.tsx b/kafka-manager-console/src/component/chart/date-picker-chart.tsx new file mode 100644 index 00000000..0e0d6d6a --- /dev/null +++ b/kafka-manager-console/src/component/chart/date-picker-chart.tsx @@ -0,0 +1,110 @@ +import * as React from 'react'; +import { DatePicker, notification, Spin } from 'component/antd'; +import moment, { Moment } from 'moment'; +import { timeStampStr } from 'constants/strategy'; +import { disabledDate } from 'lib/utils'; +import echarts from 'echarts'; + +// 引入柱状图和折线图 +import 'echarts/lib/chart/bar'; +import 'echarts/lib/chart/line'; + +// 引入提示框和标题组件 +import 'echarts/lib/component/tooltip'; +import 'echarts/lib/component/title'; +import 'echarts/lib/component/legend'; +import './index.less'; + +const { RangePicker } = DatePicker; + +interface IChartProps { + getChartData: (startTime: moment.Moment, endTime: moment.Moment) => any; + customerNode?: React.ReactNode; +} + +export class ChartWithDatePicker extends React.Component { + public state = { + startTime: moment().subtract(1, 'hour'), + endTime: moment(), + loading: false, + noData: false, + }; + + public id: HTMLDivElement = null; + public chart: echarts.ECharts; + + public getData = () => { + const { startTime, endTime } = this.state; + const { getChartData } = this.props; + this.setState({ loading: true }); + getChartData(startTime, endTime).then((data: any) => { + this.setState({ loading: false }); + this.changeChartOptions(data); + }); + } + + public componentDidMount() { + this.chart = echarts.init(this.id); + this.getData(); + window.addEventListener('resize', this.resize); + } + + public componentWillUnmount() { + window.removeEventListener('resize', this.resize); + } + + public resize = () => { + this.chart.resize(); + } + + public changeChartOptions(options: any) { + const noData = options.series.length ? false : true; + this.setState({ noData }); + this.chart.setOption(options, true); + } + + public handleTimeChange = (dates: Moment[]) => { + this.setState({ + startTime: dates[0], + endTime: dates[1], + }); + const { getChartData } = this.props; + this.setState({ loading: true }); + getChartData(dates[0], dates[1]).then((data: any) => { + this.setState({ loading: false }); + this.changeChartOptions(data); + }); + } + + public render() { + const { customerNode } = this.props; + return ( +
    +
    +
    + {customerNode} +
    +
      +
    • + +
    • +
    +
    + + {this.state.noData ?
    暂无数据
    : null} +
    this.id = id} /> + +
    + ); + } +} diff --git a/kafka-manager-console/src/component/chart/doughnut-chart.tsx b/kafka-manager-console/src/component/chart/doughnut-chart.tsx new file mode 100644 index 00000000..0b2c3ebf --- /dev/null +++ b/kafka-manager-console/src/component/chart/doughnut-chart.tsx @@ -0,0 +1,60 @@ +import * as React from 'react'; +import { Spin } from 'component/antd'; +import echarts from 'echarts/lib/echarts'; +// 引入饼状图 +import 'echarts/lib/chart/pie'; +// 引入提示框和标题组件 +import 'echarts/lib/component/tooltip'; +import 'echarts/lib/component/title'; +import 'echarts/lib/component/legend'; + +interface IPieProps { + getChartData: any; +} + +export class DoughnutChart extends React.Component { + public id: HTMLDivElement = null; + public chart: echarts.ECharts; + + public state = { + loading: true, + isNoData: false, + }; + + public getChartData = () => { + const { getChartData } = this.props; + + this.setState({ loading: true }); + const options = getChartData(); + if (!options || !options.series || !options.series.length) { + this.setState({ + isNoData: true, + loading: false, + }); + return; + } + + this.changeChartOptions(options); + } + + public changeChartOptions(options: any) { + this.chart.setOption(options, true); + this.setState({ loading: false }); + } + + public componentDidMount() { + this.chart = echarts.init(this.id); + this.getChartData(); + } + + public render() { + return ( + <> + + {this.state.isNoData ?
    暂无数据
    : null} +
    this.id = id} /> + + + ); + } +} diff --git a/kafka-manager-console/src/component/chart/index.less b/kafka-manager-console/src/component/chart/index.less new file mode 100644 index 00000000..4c0cb8d9 --- /dev/null +++ b/kafka-manager-console/src/component/chart/index.less @@ -0,0 +1,80 @@ +.status-box{ + float: left; + margin: 0 5px; + width: 100%; + .status-graph { + position: relative; + height: 48px; + width: 100%; + background: rgba(255, 255, 255, 255); + display: flex; + justify-content: space-between; + line-height: 48px; + font-family: PingFangSC-Regular; + color: rgba(0, 0, 0, 0.85); + padding: 0 5px; + margin: -15px 0; + .k-toolbar { + &>span.label { + padding: 10px; + font-size: 12px; + } + + li { + float: left; + vertical-align: middle; + line-height: 48px; + margin-right: 20px; + + &>span.label { + padding-right: 10px; + } + } + + .title-toolbar { + float: right; + right: 30px; + + span:first-child { + margin-right: 10px; + } + } + } + } + .graph-none{ + display: none; + } +} +.nothing-style { + height: 300px; + line-height: 300px; + text-align: center; +} + +.chart { + height: 400px; + padding: 10px 20px; +} +.doughnut-chart { + width: 500px; + height: 350px; +} + +.chart-no-data { + height: 0px; + display: none; +} + +.ant-spin-nested-loading { + margin: 0 auto; +} + +.no-footer { + .ant-modal-confirm-btns { + display: none; + } +} + +.no-data-info { + text-align: center; +} \ No newline at end of file diff --git a/kafka-manager-console/src/component/chart/index.tsx b/kafka-manager-console/src/component/chart/index.tsx new file mode 100644 index 00000000..befb951e --- /dev/null +++ b/kafka-manager-console/src/component/chart/index.tsx @@ -0,0 +1,4 @@ +export * from './bar-chart'; +export * from './date-picker-chart'; +export * from './doughnut-chart'; +export * from './line-chart'; diff --git a/kafka-manager-console/src/component/chart/line-chart.tsx b/kafka-manager-console/src/component/chart/line-chart.tsx new file mode 100644 index 00000000..6b5db5be --- /dev/null +++ b/kafka-manager-console/src/component/chart/line-chart.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import echarts, { EChartOption } from 'echarts/lib/echarts'; +import 'echarts/lib/chart/pie'; +import 'echarts/lib/chart/line'; +import 'echarts/lib/component/legend'; +import 'echarts/lib/component/tooltip'; +import 'echarts/lib/component/title'; +import 'echarts/lib/component/axis'; +import './index.less'; + +export interface IEchartsProps { + width?: number; + height?: number; + options?: EChartOption; +} + +export const hasData = (options: EChartOption) => { + if (options && options.series && options.series.length) return true; + return false; +}; + +export default class LineChart extends React.Component { + public id = null as HTMLDivElement; + + public myChart = null as echarts.ECharts; + + public componentDidMount() { + const { options } = this.props; + this.myChart = echarts.init(this.id); + this.myChart.setOption(options); + window.addEventListener('resize', this.resize); + } + + public componentWillUnmount() { + window.removeEventListener('resize', this.resize); + } + + public componentDidUpdate() { + this.refresh(); + } + + public refresh = () => { + const { options } = this.props; + this.myChart.setOption(options); + } + + public resize = () => { + this.myChart.resize(); + } + + public render() { + const { height, width } = this.props; + return
    this.id = id} style={{width: `${width}px`, height: `${height}px`}} />; + } +} diff --git a/kafka-manager-console/src/component/clipboard/index.tsx b/kafka-manager-console/src/component/clipboard/index.tsx new file mode 100755 index 00000000..e9fa015a --- /dev/null +++ b/kafka-manager-console/src/component/clipboard/index.tsx @@ -0,0 +1,55 @@ +import * as React from 'react'; +import ClipboardJS from 'clipboard'; +import { + message, +} from 'component/antd'; + +const triggerEvent = (eventName: string, element: Element) => { + let event; + const ele = element || document; + + event = document.createEvent('HTMLEvents'); + event.initEvent(eventName, true, true); + ele.dispatchEvent(event); +}; + +export class Clipboard extends React.Component { + public state = { + text: '', + }; + + private clipboard: any = null; + private dom: Element = null; + + public componentDidMount() { + const clipboard = this.clipboard = new ClipboardJS('.___clipboard', { + text(trigger: Element) { + return trigger.getAttribute('data-text'); + }, + }); + + clipboard.on('success', (e: any) => { + message.success('复制成功!'); + e.clearSelection(); + }); + + clipboard.on('error', (e: any) => { + message.error('复制失败!' + e); + }); + } + + public componentWillUnmount() { + this.clipboard.destroy(); + } + + public copy(text: string) { + this.setState({ text }); + setTimeout(() => triggerEvent('click', this.dom), 0); + } + + public render() { + return ( +
    this.dom = dom} /> + ); + } +} diff --git a/kafka-manager-console/src/component/expand-card/index.less b/kafka-manager-console/src/component/expand-card/index.less new file mode 100644 index 00000000..bd0bbbb8 --- /dev/null +++ b/kafka-manager-console/src/component/expand-card/index.less @@ -0,0 +1,39 @@ +.card-wrapper { + margin: 24px 0 32px; +} +.card-title { + font-family: PingFangSC-Medium; + font-size: 14px; + color: #333333; + height: 22px; + line-height: 22px; + margin: 15px 0; + display: flex; + align-items: center; + cursor: pointer; + i { + font-size: 15px; + margin-right: 8px; + } +} +.card-content { + background-color: #FAFAFA; + padding: 16px; + overflow: auto; + .chart-row { + overflow: hidden; + width: 100%; + } + .chart-row:not(:first-child) { + margin-top: 16px; + } + .chart-wrapper { + background-color: #FFFFFF; + width: calc(50% - 8px); + float: left; + padding: 16px; + } + .chart-wrapper:nth-child(2n) { + margin-left: 16px; + } +} \ No newline at end of file diff --git a/kafka-manager-console/src/component/expand-card/index.tsx b/kafka-manager-console/src/component/expand-card/index.tsx new file mode 100644 index 00000000..b583ada6 --- /dev/null +++ b/kafka-manager-console/src/component/expand-card/index.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import './index.less'; +import { Icon } from 'component/antd'; + +interface ICardProps { + title: string; + expand?: boolean; + charts?: JSX.Element[]; +} + +export class ExpandCard extends React.Component { + public state = { + innerExpand: true, + }; + + public handleClick = () => { + this.setState({ innerExpand: !this.state.innerExpand }); + } + + public render() { + let { expand } = this.props; + if (expand === undefined) expand = this.state.innerExpand; + const { charts } = this.props; + return ( +
    + {/*
    + + {this.props.title} +
    */} + {expand ? +
    + {(charts || []).map((c, index) => { + if (index % 2 !== 0) return null; + return ( +
    +
    {c}
    + {(index + 1 < charts.length) ?
    {charts[index + 1]}
    : null} +
    + ); + })} +
    : null} +
    + ); + } +} diff --git a/console/src/component/flow-table/index.tsx b/kafka-manager-console/src/component/flow-table/index.tsx similarity index 64% rename from console/src/component/flow-table/index.tsx rename to kafka-manager-console/src/component/flow-table/index.tsx index 996286ca..1f7d9be6 100644 --- a/console/src/component/flow-table/index.tsx +++ b/kafka-manager-console/src/component/flow-table/index.tsx @@ -23,25 +23,25 @@ const flowColumns = [{ title: '平均数', dataIndex: 'avr', key: 'partition_num', - sorter: (a: IFlow, b: IFlow) => a.avr - b.avr, + sorter: (a: IFlow, b: IFlow) => b.avr - a.avr, }, { title: '前1分钟', dataIndex: 'pre1', key: 'byte_input', - sorter: (a: IFlow, b: IFlow) => a.pre1 - b.pre1, + sorter: (a: IFlow, b: IFlow) => b.pre1 - a.pre1, }, { title: '前5分钟', dataIndex: 'pre5', key: 'byte_output', - sorter: (a: IFlow, b: IFlow) => a.pre5 - b.pre5, + sorter: (a: IFlow, b: IFlow) => b.pre5 - a.pre5, }, { title: '前15分钟', dataIndex: 'pre15', key: 'message', - sorter: (a: IFlow, b: IFlow) => a.pre15 - b.pre15, + sorter: (a: IFlow, b: IFlow) => b.pre15 - a.pre15, }]; export interface IFlowInfo { @@ -51,6 +51,8 @@ export interface IFlowInfo { failedFetchRequest: number[]; failedProduceRequest: number[]; messageIn: number[]; + totalFetchRequest: number[]; + totalProduceRequest: number[]; [key: string]: number[]; } @@ -59,24 +61,31 @@ export class StatusGraghCom extends React.Component { return null; } + public getLoading(): boolean { + return null; + } + public render() { const statusData = this.getData(); + const loading = this.getLoading(); if (!statusData) return null; const data: any[] = []; Object.keys(statusData).map((key) => { - const v = key === 'byteIn' || key === 'byteOut' ? statusData[key].map(i => (i / 1024).toFixed(2)) : - statusData[key].map(i => i.toFixed(2)); - const obj = { - key, - avr: v[0], - pre1: v[1], - pre5: v[2], - pre15: v[3], - }; - data.push(obj); + if (statusData[key]) { + const v = key === 'byteIn' || key === 'byteOut' ? statusData[key].map(i => i && (i / 1024).toFixed(2)) : + statusData[key].map(i => i && i.toFixed(2)); + const obj = { + key, + avr: v[0], + pre1: v[1], + pre5: v[2], + pre15: v[3], + }; + data.push(obj); + } }); return ( -

    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

    +
    ); } } diff --git a/kafka-manager-console/src/component/virtual-scroll-select.tsx b/kafka-manager-console/src/component/virtual-scroll-select.tsx new file mode 100644 index 00000000..7222856c --- /dev/null +++ b/kafka-manager-console/src/component/virtual-scroll-select.tsx @@ -0,0 +1,136 @@ +import * as React from 'react'; +import debounce from 'lodash.debounce'; +import { Select, Tooltip } from 'component/antd'; +import { ILabelValue } from 'types/base-type'; +import { searchProps } from 'constants/table'; + +interface IAttars { + mode?: 'multiple' | 'tags' | 'default' | 'combobox'; + placeholder?: string; +} + +interface ISelectProps { + onChange: (result: string[] | string) => any; + value?: string[] | string; + isDisabled?: boolean; + attrs?: IAttars; + getData: () => any; + refetchData?: boolean; // 有些页面通过store拿数据需要二次更新 +} +export class VirtualScrollSelect extends React.Component { + public static getDerivedStateFromProps(nextProps: any, prevState: any) { + if (nextProps.refetchData) { + return { + ...prevState, + refetchData: true, + }; + } + return null; + } + public state = { + optionsData: [] as ILabelValue[], + scrollPage: 0, + keyword: '', + total: 0, + refetchData: false, + }; + + public componentDidMount() { + this.getData(); + } + + public getData = async () => { + const { getData } = this.props; + if (!getData) return; + const pageSize = this.state.scrollPage; + let originData = await getData(); + + if (originData) { + originData = this.state.keyword ? + originData.filter((item: any) => item.label.includes(this.state.keyword)) : originData; + let data = [].concat(originData); + // tslint:disable-next-line:no-bitwise + const total = data.length ? data.length / 30 | 1 : 0; + data = data.splice(pageSize * 30, 30); // 每页展示30条数据 + + return this.setState({ + optionsData: data, + total, + refetchData: false, + }); + } + } + + public componentDidUpdate(prevProps: any) { + if (this.state.refetchData && !this.state.optionsData.length) { + // this.getData(); + } + } + + public handleSearch = (e: string) => { + debounce(() => { + this.setState({ + keyword: e.trim(), + scrollPage: 0, + }, () => { + this.getData(); + }); + }, 300)(); + } + + public handleSelectScroll = (e: any) => { + e.persist(); + const { target } = e; + const { scrollPage } = this.state; + debounce(() => { + if (target.scrollTop + target.offsetHeight === target.scrollHeight) { + const nextScrollPage = scrollPage + 1; + if (this.state.total <= nextScrollPage) { // 已全部拉取 + return; + } + this.setState({ + scrollPage: nextScrollPage, + }, () => { + this.getData(); + }); + } + if (target.scrollTop === 0 && scrollPage !== 0) { // 往上滚且不是第一页 + const nextScrollPage = scrollPage - 1; + this.setState({ + scrollPage: nextScrollPage, + }, () => { + this.getData(); + }); + } + }, 200)(); + } + + public render() { + // tslint:disable-next-line:prefer-const + let { value, isDisabled, attrs } = this.props; + if (attrs && (attrs.mode === 'multiple' || attrs.mode === 'tags')) { + value = value || []; + } + return ( + <> + + + ); + } +} diff --git a/kafka-manager-console/src/component/x-form-wrapper/index.tsx b/kafka-manager-console/src/component/x-form-wrapper/index.tsx new file mode 100755 index 00000000..3fbaee5e --- /dev/null +++ b/kafka-manager-console/src/component/x-form-wrapper/index.tsx @@ -0,0 +1,156 @@ +import * as React from 'react'; +import { Drawer, Modal, Button, message } from 'component/antd'; +import { XFormComponent } from 'component/x-form'; +import { IXFormWrapper } from 'types/base-type'; + +export class XFormWrapper extends React.Component { + + public state = { + confirmLoading: false, + formMap: this.props.formMap || [] as any, + formData: this.props.formData || {}, + }; + + private $formRef: any; + + public updateFormMap$(formMap?: any, formData?: any, isResetForm?: boolean, resetFields?: string[]) { + if (isResetForm) { + resetFields ? this.resetForm(resetFields) : this.resetForm(); + } + this.setState({ + formMap, + formData, + }); + } + + public render() { + const { type } = this.props; + switch (type) { + case 'drawer': + return this.renderDrawer(); + default: + return this.renderModal(); + } + } + + public renderDrawer() { + const { + visible, + title, + width, + formData, + formMap, + formLayout, + cancelText, + okText, + customRenderElement, + noform, + nofooter, + } = this.props; + + return ( + + <> + {customRenderElement} + + {!noform && ( + this.$formRef = form} + formData={formData} + formMap={formMap} + formLayout={formLayout} + />)} + {!nofooter && (
    + + +
    )} + <> + +
    + ); + } + + public renderModal() { + const { visible, title, width, formLayout, cancelText, okText, customRenderElement } = this.props; + const { formMap, formData } = this.state; + return ( + + this.$formRef = form} + formData={formData} + formMap={formMap} + formLayout={formLayout} + /> + <>{customRenderElement} + + ); + } + + public handleSubmit = () => { + this.$formRef.validateFields((error: Error, result: any) => { + if (error) { + return; + } + const { onSubmit, isWaitting } = this.props; + + if (typeof onSubmit === 'function') { + if (isWaitting) { + this.setState({ + confirmLoading: true, + }); + onSubmit(result).then(() => { + this.setState({ + confirmLoading: false, + }); + message.success('操作成功'); + this.resetForm(); + this.closeModalWrapper(); + }); + return; + } + + // tslint:disable-next-line:no-unused-expression + onSubmit && onSubmit(result); + + this.resetForm(); + this.closeModalWrapper(); + } + }); + } + + public handleCancel = () => { + const { onCancel } = this.props; + // tslint:disable-next-line:no-unused-expression + onCancel && onCancel(); + this.resetForm(); + this.closeModalWrapper(); + } + + public resetForm = (resetFields?: string[]) => { + // tslint:disable-next-line:no-unused-expression + this.$formRef && this.$formRef.resetFields(resetFields || ''); + } + + public closeModalWrapper = () => { + const { onChangeVisible } = this.props; + // tslint:disable-next-line:no-unused-expression + onChangeVisible && onChangeVisible(false); + } +} diff --git a/kafka-manager-console/src/component/x-form/index.less b/kafka-manager-console/src/component/x-form/index.less new file mode 100644 index 00000000..95152e60 --- /dev/null +++ b/kafka-manager-console/src/component/x-form/index.less @@ -0,0 +1,11 @@ +.ant-input-number { + width: 314px +} + +.footer-btn { + float: right; + + Button:first-child { + margin-right: 16px; + } +} \ No newline at end of file diff --git a/kafka-manager-console/src/component/x-form/index.tsx b/kafka-manager-console/src/component/x-form/index.tsx new file mode 100755 index 00000000..0e4047f4 --- /dev/null +++ b/kafka-manager-console/src/component/x-form/index.tsx @@ -0,0 +1,197 @@ +import * as React from 'react'; +import { Select, Input, InputNumber, Form, Switch, Checkbox, DatePicker, Radio, Upload, Button, Icon, Tooltip } from 'component/antd'; +import { searchProps } from 'constants/table'; +import './index.less'; + +const TextArea = Input.TextArea; +const { RangePicker } = DatePicker; + +export enum FormItemType { + input = 'input', + inputPassword = 'input_password', + inputNumber = 'input_number', + textArea = 'text_area', + select = 'select', + _switch = '_switch', + custom = 'custom', + checkBox = 'check_box', + datePicker = 'date_picker', + rangePicker = 'range_picker', + radioGroup = 'radio_group', + upload = 'upload', +} + +export interface IFormItem { + key: string; + label: string; + type: FormItemType; + value?: string; + // 内部组件属性注入 + attrs?: any; + // form属性注入 + formAttrs?: any; + defaultValue?: string | number | any[]; + rules?: any[]; + invisible?: boolean; + renderExtraElement?: () => JSX.Element; +} + +export interface IFormSelect extends IFormItem { + options: Array<{ key?: string | number, value: string | number, label: string, text?: string }>; +} + +interface IFormCustom extends IFormItem { + customFormItem: React.Component; +} + +interface IXFormProps { + formMap: IFormItem[]; + formData: any; + form: any; + formLayout?: any; + layout?: 'inline' | 'horizontal' | 'vertical'; +} + +class XForm extends React.Component { + + private defaultFormLayout = { + labelCol: { span: 6 }, + wrapperCol: { span: 16 }, + }; + + public onUploadFileChange = (e: any) => { + if (Array.isArray(e)) { + return e; + } + return e && e.fileList; + } + + public handleFormItem(formItem: any, formData: any) { + let initialValue = formData[formItem.key] === 0 ? 0 : (formData[formItem.key] || formItem.defaultValue || ''); + let valuePropName = 'value'; + + if (formItem.type === FormItemType.datePicker) { + initialValue = initialValue || null; + } + + // if (formItem.type === FormItemType.checkBox) { + // initialValue = formItem.defaultValue ? [formItem.defaultValue] : []; + // } + + if (formItem.type === FormItemType._switch) { + initialValue = false; + } + + // if (formItem.type === FormItemType.select && formItem.attrs + // && ['tags'].includes(formItem.attrs.mode)) { + // initialValue = formItem.defaultValue ? [formItem.defaultValue] : []; + // } + + if (formItem.type === FormItemType._switch) { + valuePropName = 'checked'; + } + + if (formItem.type === FormItemType.upload) { + valuePropName = 'fileList'; + } + + return { initialValue, valuePropName }; + } + + public render() { + const { form, formData, formMap, formLayout, layout } = this.props; + const { getFieldDecorator } = form; + return ( +
    ({})}> + {formMap.map(formItem => { + const { initialValue, valuePropName } = this.handleFormItem(formItem, formData); + + const getFieldValue = { + initialValue, + rules: formItem.rules || [{ required: false, message: '' }], + valuePropName, + }; + + if (formItem.type === FormItemType.upload) { + Object.assign(getFieldValue, { + getValueFromEvent: this.onUploadFileChange, + }); + } + return ( + !formItem.invisible && + + {getFieldDecorator(formItem.key, getFieldValue)( + this.renderFormItem(formItem), + )} + {formItem.renderExtraElement ? formItem.renderExtraElement() : null} + + ); + })} + + ); + } + + public renderFormItem(item: IFormItem) { + + switch (item.type) { + default: + case FormItemType.input: + return ; + case FormItemType.inputPassword: + return ; + case FormItemType.inputNumber: + return ; + case FormItemType.textArea: + return