Commit 2584911d888707313fd54b7b82362891337c9a80

Authored by YunaiV
1 parent 8191d9e1

code review:会员标签

Showing 15 changed files with 39 additions and 207 deletions
sql/mysql/member_tag.sql deleted
1   -create table member_tag
2   -(
3   - id bigint auto_increment comment '编号'
4   - primary key,
5   - name varchar(30) default '' not null comment '标签名称',
6   - creator varchar(64) default '' null comment '创建者',
7   - create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
8   - updater varchar(64) default '' null comment '更新者',
9   - update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
10   - deleted bit default b'0' not null comment '是否删除',
11   - tenant_id bigint default 0 not null comment '租户编号'
12   -)
13   - comment '会员标签';
14   -
15   -alter table member_user add column tag_ids varchar(255) null comment '用户标签编号列表,以逗号分隔';
16   -
17   --- 菜单 SQL
18   -INSERT INTO system_menu(
19   - name, permission, type, sort, parent_id,
20   - path, icon, component, status, component_name
21   -)
22   -VALUES (
23   - '会员标签管理', '', 2, 3, 2262,
24   - 'tag', '', 'member/tag/index', 0, 'MemberTag'
25   -);
26   -
27   --- 按钮父菜单ID
28   --- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
29   -SELECT @parentId := LAST_INSERT_ID();
30   -
31   --- 按钮 SQL
32   -INSERT INTO system_menu(
33   - name, permission, type, sort, parent_id,
34   - path, icon, component, status
35   -)
36   -VALUES (
37   - '会员标签查询', 'member:tag:query', 3, 1, @parentId,
38   - '', '', '', 0
39   -);
40   -INSERT INTO system_menu(
41   - name, permission, type, sort, parent_id,
42   - path, icon, component, status
43   -)
44   -VALUES (
45   - '会员标签创建', 'member:tag:create', 3, 2, @parentId,
46   - '', '', '', 0
47   -);
48   -INSERT INTO system_menu(
49   - name, permission, type, sort, parent_id,
50   - path, icon, component, status
51   -)
52   -VALUES (
53   - '会员标签更新', 'member:tag:update', 3, 3, @parentId,
54   - '', '', '', 0
55   -);
56   -INSERT INTO system_menu(
57   - name, permission, type, sort, parent_id,
58   - path, icon, component, status
59   -)
60   -VALUES (
61   - '会员标签删除', 'member:tag:delete', 3, 4, @parentId,
62   - '', '', '', 0
63   -);
64   -INSERT INTO system_menu(
65   - name, permission, type, sort, parent_id,
66   - path, icon, component, status
67   -)
68   -VALUES (
69   - '会员标签导出', 'member:tag:export', 3, 5, @parentId,
70   - '', '', '', 0
71   -);
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/MemberTagController.java
... ... @@ -2,9 +2,10 @@ package cn.iocoder.yudao.module.member.controller.admin.tag;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
6   -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
7   -import cn.iocoder.yudao.module.member.controller.admin.tag.vo.*;
  5 +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO;
  6 +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO;
  7 +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagRespVO;
  8 +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO;
8 9 import cn.iocoder.yudao.module.member.convert.tag.MemberTagConvert;
9 10 import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
10 11 import cn.iocoder.yudao.module.member.service.tag.MemberTagService;
... ... @@ -16,14 +17,11 @@ import org.springframework.validation.annotation.Validated;
16 17 import org.springframework.web.bind.annotation.*;
17 18  
18 19 import javax.annotation.Resource;
19   -import javax.servlet.http.HttpServletResponse;
20 20 import javax.validation.Valid;
21   -import java.io.IOException;
22 21 import java.util.Collection;
23 22 import java.util.List;
24 23  
25 24 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
26   -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
27 25  
28 26 @Tag(name = "管理后台 - 会员标签")
29 27 @RestController
... ... @@ -84,16 +82,4 @@ public class MemberTagController {
84 82 return success(MemberTagConvert.INSTANCE.convertPage(pageResult));
85 83 }
86 84  
87   - @GetMapping("/export-excel")
88   - @Operation(summary = "导出会员标签 Excel")
89   - @PreAuthorize("@ss.hasPermission('member:tag:export')")
90   - @OperateLog(type = EXPORT)
91   - public void exportTagExcel(@Valid MemberTagExportReqVO exportReqVO,
92   - HttpServletResponse response) throws IOException {
93   - List<MemberTagDO> list = tagService.getTagList(exportReqVO);
94   - // 导出 Excel
95   - List<MemberTagExcelVO> datas = MemberTagConvert.INSTANCE.convertList02(list);
96   - ExcelUtils.write(response, "会员标签.xls", "数据", MemberTagExcelVO.class, datas);
97   - }
98   -
99 85 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagExcelVO.java deleted
1   -package cn.iocoder.yudao.module.member.controller.admin.tag.vo;
2   -
3   -import com.alibaba.excel.annotation.ExcelProperty;
4   -import lombok.Data;
5   -
6   -import java.time.LocalDateTime;
7   -
8   -/**
9   - * 会员标签 Excel VO
10   - *
11   - * @author 芋道源码
12   - */
13   -@Data
14   -public class MemberTagExcelVO {
15   -
16   - @ExcelProperty("编号")
17   - private Long id;
18   -
19   - @ExcelProperty("标签名称")
20   - private String name;
21   -
22   - @ExcelProperty("创建时间")
23   - private LocalDateTime createTime;
24   -
25   -}
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagExportReqVO.java deleted
1   -package cn.iocoder.yudao.module.member.controller.admin.tag.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import org.springframework.format.annotation.DateTimeFormat;
6   -
7   -import java.time.LocalDateTime;
8   -
9   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
10   -
11   -@Schema(description = "管理后台 - 会员标签 Excel 导出 Request VO,参数和 MemberTagPageReqVO 是一致的")
12   -@Data
13   -public class MemberTagExportReqVO {
14   -
15   - @Schema(description = "标签名称", example = "李四")
16   - private String name;
17   -
18   - @Schema(description = "创建时间")
19   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
20   - private LocalDateTime[] createTime;
21   -
22   -}
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/MemberUserController.java
1 1 package cn.iocoder.yudao.module.member.controller.admin.user;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
... ... @@ -19,11 +20,13 @@ import org.springframework.web.bind.annotation.*;
19 20  
20 21 import javax.annotation.Resource;
21 22 import javax.validation.Valid;
22   -import java.util.*;
  23 +import java.util.Collection;
  24 +import java.util.List;
  25 +import java.util.Objects;
  26 +import java.util.Set;
23 27 import java.util.stream.Collectors;
24 28  
25 29 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
26   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
27 30  
28 31 @Tag(name = "管理后台 - 会员用户")
29 32 @RestController
... ... @@ -58,6 +61,9 @@ public class MemberUserController {
58 61 @PreAuthorize("@ss.hasPermission('member:user:query')")
59 62 public CommonResult<PageResult<MemberUserRespVO>> getUserPage(@Valid MemberUserPageReqVO pageVO) {
60 63 PageResult<MemberUserDO> pageResult = memberUserService.getUserPage(pageVO);
  64 + if (CollUtil.isEmpty(pageResult.getList())) {
  65 + return success(PageResult.empty());
  66 + }
61 67  
62 68 // 处理会员标签返显
63 69 Set<Long> tagIds = pageResult.getList().stream()
... ... @@ -66,9 +72,7 @@ public class MemberUserController {
66 72 .flatMap(Collection::stream)
67 73 .collect(Collectors.toSet());
68 74 List<MemberTagDO> tags = memberTagService.getTagList(tagIds);
69   - Map<Long, String> tagNameMap = convertMap(tags, MemberTagDO::getId, MemberTagDO::getName);
70   -
71   - return success(MemberUserConvert.INSTANCE.convertPage(pageResult, tagNameMap));
  75 + return success(MemberUserConvert.INSTANCE.convertPage(pageResult, tags));
72 76 }
73 77  
74 78 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java
... ... @@ -50,7 +50,7 @@ public class MemberUserBaseVO {
50 50 @Schema(description = "会员备注", example = "我是小备注")
51 51 private String mark;
52 52  
53   - @Schema(description = "会员标签")
  53 + @Schema(description = "会员标签", example = "[1, 2]")
54 54 private List<Long> tagIds;
55 55  
56 56 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java
... ... @@ -32,7 +32,7 @@ public class MemberUserPageReqVO extends PageParam {
32 32 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
33 33 private LocalDateTime[] createTime;
34 34  
35   - @Schema(description = "会员标签")
  35 + @Schema(description = "会员标签", example = "[1, 2]")
36 36 private List<Long> tagIds;
37 37  
38 38 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserRespVO.java
... ... @@ -32,6 +32,7 @@ public class MemberUserRespVO extends MemberUserBaseVO {
32 32  
33 33 // ========== 其它信息 ==========
34 34  
35   - @Schema(description = "会员标签")
  35 + @Schema(description = "会员标签", example = "[红色, 快乐]")
36 36 private List<String> tagNames;
  37 +
37 38 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/tag/MemberTagConvert.java
1 1 package cn.iocoder.yudao.module.member.convert.tag;
2 2  
3   -import java.util.*;
4   -
5 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6   -
  4 +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO;
  5 +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagRespVO;
  6 +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO;
  7 +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
7 8 import org.mapstruct.Mapper;
8 9 import org.mapstruct.factory.Mappers;
9   -import cn.iocoder.yudao.module.member.controller.admin.tag.vo.*;
10   -import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
  10 +
  11 +import java.util.List;
11 12  
12 13 /**
13 14 * 会员标签 Convert
... ... @@ -29,6 +30,4 @@ public interface MemberTagConvert {
29 30  
30 31 PageResult<MemberTagRespVO> convertPage(PageResult<MemberTagDO> page);
31 32  
32   - List<MemberTagExcelVO> convertList02(List<MemberTagDO> list);
33   -
34 33 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/MemberUserConvert.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
5 5 import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserRespVO;
6 6 import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
7 7 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserInfoRespVO;
  8 +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
8 9 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
9 10 import org.mapstruct.Mapper;
10 11 import org.mapstruct.factory.Mappers;
... ... @@ -13,6 +14,7 @@ import java.util.List;
13 14 import java.util.Map;
14 15  
15 16 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  17 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
16 18  
17 19 @Mapper
18 20 public interface MemberUserConvert {
... ... @@ -32,8 +34,9 @@ public interface MemberUserConvert {
32 34 MemberUserRespVO convert03(MemberUserDO bean);
33 35  
34 36 default PageResult<MemberUserRespVO> convertPage(PageResult<MemberUserDO> pageResult,
35   - Map<Long, String> tagMap) {
  37 + List<MemberTagDO> tags) {
36 38 PageResult<MemberUserRespVO> result = convertPage(pageResult);
  39 + Map<Long, String> tagMap = convertMap(tags, MemberTagDO::getId, MemberTagDO::getName);
37 40 for (MemberUserRespVO vo : result.getList()) {
38 41 vo.setTagNames(convertList(vo.getTagIds(), tagMap::get));
39 42 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/tag/MemberTagMapper.java
... ... @@ -3,13 +3,10 @@ package cn.iocoder.yudao.module.member.dal.mysql.tag;
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6   -import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagExportReqVO;
7 6 import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO;
8 7 import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
9 8 import org.apache.ibatis.annotations.Mapper;
10 9  
11   -import java.util.List;
12   -
13 10 /**
14 11 * 会员标签 Mapper
15 12 *
... ... @@ -25,13 +22,6 @@ public interface MemberTagMapper extends BaseMapperX&lt;MemberTagDO&gt; {
25 22 .orderByDesc(MemberTagDO::getId));
26 23 }
27 24  
28   - default List<MemberTagDO> selectList(MemberTagExportReqVO reqVO) {
29   - return selectList(new LambdaQueryWrapperX<MemberTagDO>()
30   - .likeIfPresent(MemberTagDO::getName, reqVO.getName())
31   - .betweenIfPresent(MemberTagDO::getCreateTime, reqVO.getCreateTime())
32   - .orderByDesc(MemberTagDO::getId));
33   - }
34   -
35 25 default boolean exists(Long id, String name) {
36 26 return exists(new LambdaQueryWrapperX<MemberTagDO>()
37 27 .neIfPresent(MemberTagDO::getId, id)
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
... ... @@ -30,13 +30,14 @@ public interface MemberUserMapper extends BaseMapperX&lt;MemberUserDO&gt; {
30 30 }
31 31  
32 32 default PageResult<MemberUserDO> selectPage(MemberUserPageReqVO reqVO) {
  33 + // 处理 tagIds 过滤条件
33 34 String tagIdSql = "";
34 35 if (CollUtil.isNotEmpty(reqVO.getTagIds())) {
35 36 tagIdSql = reqVO.getTagIds().stream()
36 37 .map(tagId -> "FIND_IN_SET(" + tagId + ", tag_ids)")
37 38 .collect(Collectors.joining(" OR "));
38 39 }
39   -
  40 + // 分页查询
40 41 return selectPage(reqVO, new LambdaQueryWrapperX<MemberUserDO>()
41 42 .likeIfPresent(MemberUserDO::getMobile, reqVO.getMobile())
42 43 .betweenIfPresent(MemberUserDO::getLoginDate, reqVO.getLoginDate())
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/tag/MemberTagService.java
1 1 package cn.iocoder.yudao.module.member.service.tag;
2 2  
3   -import java.util.*;
4   -import javax.validation.*;
5   -import cn.iocoder.yudao.module.member.controller.admin.tag.vo.*;
6   -import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
7 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO;
  5 +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO;
  6 +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO;
  7 +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
  8 +
  9 +import javax.validation.Valid;
  10 +import java.util.Collection;
  11 +import java.util.List;
8 12  
9 13 /**
10 14 * 会员标签 Service 接口
... ... @@ -59,12 +63,4 @@ public interface MemberTagService {
59 63 */
60 64 PageResult<MemberTagDO> getTagPage(MemberTagPageReqVO pageReqVO);
61 65  
62   - /**
63   - * 获得会员标签列表, 用于 Excel 导出
64   - *
65   - * @param exportReqVO 查询条件
66   - * @return 会员标签列表
67   - */
68   - List<MemberTagDO> getTagList(MemberTagExportReqVO exportReqVO);
69   -
70 66 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/tag/MemberTagServiceImpl.java
... ... @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.collection.ListUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO;
7   -import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagExportReqVO;
8 7 import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO;
9 8 import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO;
10 9 import cn.iocoder.yudao.module.member.convert.tag.MemberTagConvert;
... ... @@ -63,6 +62,8 @@ public class MemberTagServiceImpl implements MemberTagService {
63 62 tagMapper.deleteById(id);
64 63 }
65 64  
  65 + // TODO @疯狂:校验 tag name 不重复,参考 validateMobileUnique 方法,Mapper 尽量逻辑通用,处理交给 Service
  66 +
66 67 private void validateTagExists(Long id) {
67 68 if (tagMapper.selectById(id) == null) {
68 69 throw exception(TAG_NOT_EXISTS);
... ... @@ -94,9 +95,4 @@ public class MemberTagServiceImpl implements MemberTagService {
94 95 return tagMapper.selectPage(pageReqVO);
95 96 }
96 97  
97   - @Override
98   - public List<MemberTagDO> getTagList(MemberTagExportReqVO exportReqVO) {
99   - return tagMapper.selectList(exportReqVO);
100   - }
101   -
102 98 }
... ...
yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/tag/MemberTagServiceImplTest.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.member.service.tag;
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 5 import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO;
6   -import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagExportReqVO;
7 6 import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO;
8 7 import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO;
9 8 import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
... ... @@ -12,7 +11,6 @@ import org.junit.jupiter.api.Test;
12 11 import org.springframework.context.annotation.Import;
13 12  
14 13 import javax.annotation.Resource;
15   -import java.util.List;
16 14  
17 15 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
18 16 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
... ... @@ -126,28 +124,4 @@ public class MemberTagServiceImplTest extends BaseDbUnitTest {
126 124 assertPojoEquals(dbTag, pageResult.getList().get(0));
127 125 }
128 126  
129   - @Test
130   - public void testGetTagList() {
131   - // mock 数据
132   - MemberTagDO dbTag = randomPojo(MemberTagDO.class, o -> { // 等会查询到
133   - o.setName("test");
134   - o.setCreateTime(buildTime(2023, 2, 18));
135   - });
136   - tagMapper.insert(dbTag);
137   - // 测试 name 不匹配
138   - tagMapper.insert(cloneIgnoreId(dbTag, o -> o.setName("ne")));
139   - // 测试 createTime 不匹配
140   - tagMapper.insert(cloneIgnoreId(dbTag, o -> o.setCreateTime(null)));
141   - // 准备参数
142   - MemberTagExportReqVO reqVO = new MemberTagExportReqVO();
143   - reqVO.setName("test");
144   - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
145   -
146   - // 调用
147   - List<MemberTagDO> list = tagService.getTagList(reqVO);
148   - // 断言
149   - assertEquals(1, list.size());
150   - assertPojoEquals(dbTag, list.get(0));
151   - }
152   -
153 127 }
... ...