Commit 4d5ab609 authored by dsq's avatar dsq

脚本

parent b6616e1f
...@@ -13,3 +13,4 @@ ...@@ -13,3 +13,4 @@
.externalNativeBuild .externalNativeBuild
.cxx .cxx
local.properties local.properties
composeApp/src/commonMain/kotlin/com/dong/maxhap/HapTestPage
# MaxHap 项目
这是一个基于 Kotlin Multiplatform 和 Jetpack Compose 的跨平台应用项目,支持 Android 和 HarmonyOS 平台。
## 项目结构
```
MaxHap/
├── composeApp/ # 共享的 Compose 代码
├── androidApp/ # Android 特定代码
├── harmonyApp/ # HarmonyOS 特定代码
├── iosApp/ # iOS 特定代码(如果需要)
└── scripts/ # 项目脚本工具
```
## 脚本工具
项目提供了几个实用的脚本工具来帮助开发和测试:
### 1. 批量生成测试文件脚本
#### generate_hap_test_files.sh
生成1000个Kotlin测试文件,每个文件包含1000个Text组件。
**功能特性:**
- 生成1000个.kt文件(MaxFile0001.kt 到 MaxFile1000.kt)
- 每个文件以 `@Composable` 开头
- 包含 `internal fun Max{数字}()` 函数定义
- 使用指定的导入语句:
- `import androidx.compose.foundation.layout.Column`
- `import androidx.compose.material.Text`
- `import androidx.compose.runtime.Composable`
- 每个函数包含1000个Text组件,被Column包裹
- 每个Text都有不同的颜色和字体大小(12sp-36sp)
**使用方法:**
```bash
# 给脚本添加执行权限(首次使用)
chmod +x generate_hap_test_files.sh
# 运行脚本生成文件
./generate_hap_test_files.sh
```
**生成文件位置:**
```
composeApp/src/commonMain/kotlin/com/dong/maxhap/HapTestPage/
```
### 2. 清理测试文件脚本
#### cleanup_hap_test_files.sh(交互式)
安全删除所有生成的测试文件,带确认提示。
**功能特性:**
- 显示要删除的文件数量
- 需要用户确认才执行删除
- 删除完成后可选择是否删除空目录
**使用方法:**
```bash
# 给脚本添加执行权限(首次使用)
chmod +x cleanup_hap_test_files.sh
# 运行交互式清理
./cleanup_hap_test_files.sh
```
#### quick_cleanup.sh(快速版)
直接删除所有测试文件,无需确认。
**功能特性:**
- 直接删除,无需用户交互
- 执行速度快
- 适合自动化脚本调用
**使用方法:**
```bash
# 给脚本添加执行权限(首次使用)
chmod +x quick_cleanup.sh
# 快速清理所有文件
./quick_cleanup.sh
```
## 开发环境
### 技术栈
- Kotlin Multiplatform
- Jetpack Compose
- Android SDK
- HarmonyOS SDK
### 构建工具
- Gradle
- Hvigor(HarmonyOS构建工具)
## 构建和运行
### Android
```bash
# 构建Debug版本
./gradlew assembleDebug
# 运行Android应用
./gradlew installDebug
```
### HarmonyOS
```bash
# 构建HarmonyOS应用
cd harmonyApp
hvigorw assembleHap
```
## 项目特点
- 跨平台共享代码
- 响应式UI设计
- 模块化架构
- 支持多种构建变体
## 注意事项
1. 批量生成的测试文件主要用于应用体积测试
2. 清理脚本只会删除特定格式的文件(MaxFile*.kt)
3. 建议在使用清理脚本前备份重要数据
\ No newline at end of file
#!/bin/bash
# 设置目标目录
TARGET_DIR="composeApp/src/commonMain/kotlin/com/dong/maxhap/HapTestPage"
# 检查目录是否存在
if [ ! -d "$TARGET_DIR" ]; then
echo "目录 $TARGET_DIR 不存在"
exit 1
fi
# 统计要删除的文件数量
FILE_COUNT=$(find "$TARGET_DIR" -name "MaxFile*.kt" -type f | wc -l)
if [ "$FILE_COUNT" -eq 0 ]; then
echo "没有找到需要删除的MaxFile*.kt文件"
exit 0
fi
echo "找到 $FILE_COUNT 个文件需要删除"
# 确认删除
echo "警告:这将删除 $TARGET_DIR 目录下的所有 MaxFile*.kt 文件"
read -p "是否继续?(y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "取消删除操作"
exit 0
fi
# 删除文件
echo "正在删除文件..."
find "$TARGET_DIR" -name "MaxFile*.kt" -type f -delete
# 检查删除结果
REMAINING_COUNT=$(find "$TARGET_DIR" -name "MaxFile*.kt" -type f | wc -l)
if [ "$REMAINING_COUNT" -eq 0 ]; then
echo "删除成功!所有MaxFile*.kt文件已删除"
# 询问是否删除空目录
if [ -z "$(ls -A "$TARGET_DIR")" ]; then
read -p "HapTestPage目录现在为空,是否删除该目录?(y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
rmdir "$TARGET_DIR"
echo "目录 $TARGET_DIR 已删除"
else
echo "保留空目录 $TARGET_DIR"
fi
fi
else
echo "删除完成,但仍剩余 $REMAINING_COUNT 个文件"
fi
\ No newline at end of file
...@@ -250,7 +250,10 @@ tasks.register("makeIt300MB") { ...@@ -250,7 +250,10 @@ tasks.register("makeIt300MB") {
doLast { doLast {
// 生成 10 万行 @Composable // 生成 10 万行 @Composable
repeat(1000) { fileIndex -> repeat(1000) { fileIndex ->
File("src/commonMain/kotlin/com/dong/maxhap/demos/hap/Huge$fileIndex.kt").writeText("""
val hapDir = File("src/commonMain/kotlin/com/dong/maxhap/demos/hap")
hapDir.mkdirs()
File(hapDir, "Huge$fileIndex.kt").writeText("""
@Composable @Composable
fun HugeFunction$fileIndex() { fun HugeFunction$fileIndex() {
${(1..100).joinToString("\n") { ${(1..100).joinToString("\n") {
......
package com.dong.maxhap.demos.Hap
class hap {
}
\ No newline at end of file
#!/bin/bash
# 设置目标目录
TARGET_DIR="composeApp/src/commonMain/kotlin/com/dong/maxhap/HapTestPage"
# 创建目录
mkdir -p "$TARGET_DIR"
# 生成1000个文件
for i in $(seq 1 1200); do
# 格式化文件名,确保4位数字
FILENAME=$(printf "MaxFile%04d.kt" $i)
FILEPATH="$TARGET_DIR/$FILENAME"
# 生成函数名
FUNCTION_NAME="Max$i"
# 开始写入文件
echo "import androidx.compose.foundation.layout.Column" > "$FILEPATH"
echo "import androidx.compose.material.Text" >> "$FILEPATH"
echo "import androidx.compose.runtime.Composable" >> "$FILEPATH"
echo "" >> "$FILEPATH"
echo "@Composable" >> "$FILEPATH"
echo "internal fun $FUNCTION_NAME() {" >> "$FILEPATH"
echo " Column {" >> "$FILEPATH"
# 生成1000个Text组件,每个有不同的颜色和大小
for j in $(seq 1 300); do
# 计算颜色值(基于索引生成不同颜色)
RED=$(( (j * 17) % 256 ))
GREEN=$(( (j * 31) % 256 ))
BLUE=$(( (j * 47) % 256 ))
echo " Text(\"这是测试$j\", color = androidx.compose.ui.graphics.Color($RED, $GREEN, $BLUE))" >> "$FILEPATH"
done
# 结束Column
echo " }" >> "$FILEPATH"
# 结束函数
echo "}" >> "$FILEPATH"
# 显示进度
if [ $((i % 100)) -eq 0 ]; then
echo "已生成 $i 个文件"
fi
done
echo "成功生成 1000 个 Kotlin 文件到 $TARGET_DIR 目录"
\ No newline at end of file
# HarmonyOS嵌套页面项目说明
## 项目概述
这是一个基于DevEco Studio 6.0.0+ 和 API 20+ 的HarmonyOS应用项目,实现了5层深度的页面嵌套结构,打包体积约300MB。
## 项目结构
### 页面层级结构
```
首页 (Index.ets)
├── 第一层 (Level1Page.ets) - 基础功能展示
├── 第二层 (Level2Page.ets) - 交互功能增强
├── 第三层 (Level3Page.ets) - 数据处理核心
├── 第四层 (Level4Page.ets) - 高级功能集成
└── 第五层 (Level5Page.ets) - 最终展示层
```
### 主要特性
- **层层嵌套**: 5层深度的页面导航结构
- **现代化UI**: Material Design风格界面
- **丰富交互**: 包含图表、统计数据、控制面板等多种组件
- **大体积资源**: 300MB资源文件用于体积测试
- **完整导航**: 支持前进、后退、跳转等导航操作
## 技术栈
- DevEco Studio 6.0.0+
- HarmonyOS API 20+
- ArkTS语言
- Compose UI框架
- Router导航系统
## 文件说明
### 页面文件 (`entry/src/main/ets/pages/`)
- `Index.ets`: 应用首页,包含启动导航按钮
- `Level1Page.ets`: 第一层页面,基础功能展示
- `Level2Page.ets`: 第二层页面,交互功能增强
- `Level3Page.ets`: 第三层页面,数据处理核心
- `Level4Page.ets`: 第四层页面,高级功能集成
- `Level5Page.ets`: 第五层页面,最终展示层
### 资源文件 (`entry/src/main/resources/base/media/`)
- `large_binary_file.bin`: 50MB大文件
- `medium_file_1.bin`: 30MB中等文件
- `medium_file_2.bin`: 25MB中等文件
- `background_image.png`: 15MB图片文件
- `icon_pack.zip`: 40MB图标包
- `database_dump.sql`: 60MB数据库导出
- `video_tutorial.mp4`: 45MB视频教程
- `documentation.pdf`: 35MB文档
- `data_sample_1.json`: JSON数据样本
### 配置文件
- `main_pages.json`: 页面路由配置文件
- `build-profile.json5`: 构建配置文件
## 常见问题解决
### "Nothing to run on" 问题解决
如果遇到"Nothing to run on"错误,请按以下步骤操作:
1. **检查配置文件语法**
- 确保所有JSON文件语法正确
- 移除JSON中的注释
- 检查逗号使用是否规范
2. **重新同步项目**
- 在DevEco Studio中选择 File -> Sync Project with Gradle Files
- 等待同步完成
3. **清理并重建**
- Build -> Clean Project
- Build -> Rebuild Project
4. **检查设备连接**
- 确保HarmonyOS设备已正确连接
- 检查设备开发者模式是否开启
5. **验证资源打包**
- 检查`entry/src/main/resources/base/media/`目录
- 确认300MB资源文件存在
### 路由相关问题修复
- 统一使用HarmonyOS API 20+标准路由API (`@ohos.router`)
- 使用`router.clear()`方法正确清除页面历史记录
- 移除了API 20以下的兼容性方法
- 所有页面导航均符合HarmonyOS最新规范
### 组件使用规范修复
- 修正了Button组件的错误用法:带label参数的Button不能包含子组件
- 统一使用标准的Button({...}) { Text(...) }语法
- 确保所有UI组件符合HarmonyOS API 20+规范
### 文件格式规范修复
- 修复了页面文件末尾缺少换行符的问题
- 确保所有.ets文件都以换行符正确结尾
- 符合ArkTS编译器的文件格式要求
### 类型安全规范修复
- 为所有变量和函数参数添加了明确的类型声明
- 替换了`any``Object`类型为具体的接口类型
- 为ForEach循环中的参数添加了类型注解
- 确保代码符合ArkTS严格的类型检查要求
### UI组件语法规范修复
- 修正了路由导航必须在onClick事件处理器中的使用规范
- 修复了selfAlign属性错误应用于Text组件的问题
- 确保对象字面量都有对应的接口声明
- 统一了UI组件属性的正确使用方式
### 包体积验证
构建完成后,检查生成的HAP文件大小:
```bash
ls -la entry/build/default/outputs/default/*.hap
```
应该看到接近300MB的HAP文件。
### 在DevEco Studio中打开
1. 启动DevEco Studio 6.0.0+
2. 选择"Open an existing project"
3. 导航到项目根目录
4. 等待项目同步完成
### 构建项目
在DevEco Studio中:
1. 选择Build菜单
2. 点击Build HAP(s)/APP(s)
3. 选择相应的构建配置
### 运行应用
1. 连接HarmonyOS设备或启动模拟器
2. 点击Run按钮
3. 选择目标设备运行
## 导航流程
1. 首页点击"开始嵌套之旅"按钮
2. 依次进入各层页面
3. 每层页面都有"返回"和"进入下一层"按钮
4. 第五层页面提供"返回首页"和"重新开始"选项
## 项目统计
- **总代码行数**: ~2095行
- **页面数量**: 6个 (包括首页)
- **嵌套深度**: 5层
- **资源文件**: 9个
- **预计包体积**: ~300MB
- **开发时间**: 约2小时
## 注意事项
- 项目专为DevEco Studio 6.0.0+设计
- 需要HarmonyOS API 20+环境支持
- 大体积资源文件仅用于测试目的
- 所有页面保持原有首页显示不变的基础上添加新功能
## 验证要点
✅ 页面嵌套结构完整
✅ 导航功能正常
✅ UI显示正确
✅ 资源文件齐全
✅ 配置文件正确
✅ 符合300MB体积要求
\ No newline at end of file
...@@ -66,9 +66,6 @@ typedef struct { ...@@ -66,9 +66,6 @@ typedef struct {
typedef struct { typedef struct {
libkn_KNativePtr pinned; libkn_KNativePtr pinned;
} libkn_kref_com_dong_maxhap_Platform; } libkn_kref_com_dong_maxhap_Platform;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_maxhap_demos_Hap_hap;
typedef struct { typedef struct {
libkn_KNativePtr pinned; libkn_KNativePtr pinned;
} libkn_kref_com_dong_maxhap_demos_game_Game2048State; } libkn_kref_com_dong_maxhap_demos_game_Game2048State;
...@@ -184,7 +181,6 @@ typedef struct { ...@@ -184,7 +181,6 @@ typedef struct {
libkn_KNativePtr pinned; libkn_KNativePtr pinned;
} libkn_kref_com_dong_maxhap_OhosPlatform; } libkn_kref_com_dong_maxhap_OhosPlatform;
extern void* MainArkUIViewController(void* env);
extern void androidx_compose_ui_arkui_ArkUIViewController_aboutToAppear(void* controllerRef); extern void androidx_compose_ui_arkui_ArkUIViewController_aboutToAppear(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_aboutToDisappear(void* controllerRef); extern void androidx_compose_ui_arkui_ArkUIViewController_aboutToDisappear(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_cancelSyncRefresh(void* controllerRef, libkn_KInt refreshId); extern void androidx_compose_ui_arkui_ArkUIViewController_cancelSyncRefresh(void* controllerRef, libkn_KInt refreshId);
...@@ -217,6 +213,7 @@ extern void androidx_compose_ui_arkui_ArkUIViewController_setRootView(void* cont ...@@ -217,6 +213,7 @@ extern void androidx_compose_ui_arkui_ArkUIViewController_setRootView(void* cont
extern void androidx_compose_ui_arkui_ArkUIViewController_setUIContext(void* controllerRef, void* uiContext); extern void androidx_compose_ui_arkui_ArkUIViewController_setUIContext(void* controllerRef, void* uiContext);
extern void androidx_compose_ui_arkui_ArkUIViewController_setXComponentRender(void* controllerRef, void* render); extern void androidx_compose_ui_arkui_ArkUIViewController_setXComponentRender(void* controllerRef, void* render);
extern void androidx_compose_ui_arkui_init(void* env, void* exports); extern void androidx_compose_ui_arkui_init(void* env, void* exports);
extern void* MainArkUIViewController(void* env);
typedef struct { typedef struct {
/* Service functions. */ /* Service functions. */
...@@ -254,15 +251,50 @@ typedef struct { ...@@ -254,15 +251,50 @@ typedef struct {
struct { struct {
struct { struct {
struct { struct {
struct {
struct {
struct {
void (*_Export_ArkUIViewController_aboutToAppear)(void* controllerRef);
void (*_Export_ArkUIViewController_aboutToDisappear)(void* controllerRef);
void (*_Export_ArkUIViewController_cancelSyncRefresh)(void* controllerRef, libkn_KInt refreshId);
void (*_Export_ArkUIViewController_dispatchHoverEvent)(void* controllerRef);
void (*_Export_ArkUIViewController_dispatchMouseEvent)(void* controllerRef);
libkn_KBoolean (*_Export_ArkUIViewController_dispatchTouchEvent)(void* controllerRef, void* nativeTouchEvent, libkn_KBoolean ignoreInteropView);
const char* (*_Export_ArkUIViewController_getId)(void* controllerRef);
void* (*_Export_ArkUIViewController_getXComponentRender)(void* controllerRef);
void (*_Export_ArkUIViewController_keyboardWillHide)(void* controllerRef);
void (*_Export_ArkUIViewController_keyboardWillShow)(void* controllerRef, libkn_KFloat keyboardHeight);
libkn_KBoolean (*_Export_ArkUIViewController_onBackPress)(void* controllerRef);
void (*_Export_ArkUIViewController_onFinalize)(void* controllerRef);
void (*_Export_ArkUIViewController_onFocusEvent)(void* controllerRef);
void (*_Export_ArkUIViewController_onFrame)(void* controllerRef, libkn_KLong timestamp, libkn_KLong targetTimestamp);
void (*_Export_ArkUIViewController_onKeyEvent)(void* controllerRef);
void (*_Export_ArkUIViewController_onPageHide)(void* controllerRef);
void (*_Export_ArkUIViewController_onPageShow)(void* controllerRef);
void (*_Export_ArkUIViewController_onSurfaceChanged)(void* controllerRef, libkn_KInt width, libkn_KInt height);
void (*_Export_ArkUIViewController_onSurfaceCreated)(void* controllerRef, void* xcomponentPtr, libkn_KInt width, libkn_KInt height);
void (*_Export_ArkUIViewController_onSurfaceDestroyed)(void* controllerRef);
void (*_Export_ArkUIViewController_onSurfaceHide)(void* controllerRef);
void (*_Export_ArkUIViewController_onSurfaceShow)(void* controllerRef);
libkn_KInt (*_Export_ArkUIViewController_requestSyncRefresh)(void* controllerRef);
const char* (*_Export_ArkUIViewController_sendMessage)(void* controllerRef, const char* type, const char* message);
void (*_Export_ArkUIViewController_setContext)(void* controllerRef, void* context);
void (*_Export_ArkUIViewController_setEnv)(void* controllerRef, void* env);
void (*_Export_ArkUIViewController_setId)(void* controllerRef, const char* id);
void (*_Export_ArkUIViewController_setMessenger)(void* controllerRef, void* messenger);
void (*_Export_ArkUIViewController_setRootView)(void* controllerRef, void* backRootView, void* foreRootView, void* touchableRootView);
void (*_Export_ArkUIViewController_setUIContext)(void* controllerRef, void* uiContext);
void (*_Export_ArkUIViewController_setXComponentRender)(void* controllerRef, void* render);
void (*_Export_ArkUIViewInitializer_init)(void* env, void* exports);
} arkui;
} ui;
} export_;
} compose;
} androidx;
struct { struct {
struct { struct {
struct { struct {
struct { struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_maxhap_demos_Hap_hap (*hap)();
} hap;
libkn_KInt (*com_dong_maxhap_demos_Hap_hap$stableprop_getter)();
} Hap;
struct { struct {
struct { struct {
libkn_KType* (*_type)(void); libkn_KType* (*_type)(void);
...@@ -560,48 +592,6 @@ typedef struct { ...@@ -560,48 +592,6 @@ typedef struct {
} maxhap; } maxhap;
} dong; } dong;
} com; } com;
struct {
struct {
struct {
struct {
struct {
void (*_Export_ArkUIViewController_aboutToAppear)(void* controllerRef);
void (*_Export_ArkUIViewController_aboutToDisappear)(void* controllerRef);
void (*_Export_ArkUIViewController_cancelSyncRefresh)(void* controllerRef, libkn_KInt refreshId);
void (*_Export_ArkUIViewController_dispatchHoverEvent)(void* controllerRef);
void (*_Export_ArkUIViewController_dispatchMouseEvent)(void* controllerRef);
libkn_KBoolean (*_Export_ArkUIViewController_dispatchTouchEvent)(void* controllerRef, void* nativeTouchEvent, libkn_KBoolean ignoreInteropView);
const char* (*_Export_ArkUIViewController_getId)(void* controllerRef);
void* (*_Export_ArkUIViewController_getXComponentRender)(void* controllerRef);
void (*_Export_ArkUIViewController_keyboardWillHide)(void* controllerRef);
void (*_Export_ArkUIViewController_keyboardWillShow)(void* controllerRef, libkn_KFloat keyboardHeight);
libkn_KBoolean (*_Export_ArkUIViewController_onBackPress)(void* controllerRef);
void (*_Export_ArkUIViewController_onFinalize)(void* controllerRef);
void (*_Export_ArkUIViewController_onFocusEvent)(void* controllerRef);
void (*_Export_ArkUIViewController_onFrame)(void* controllerRef, libkn_KLong timestamp, libkn_KLong targetTimestamp);
void (*_Export_ArkUIViewController_onKeyEvent)(void* controllerRef);
void (*_Export_ArkUIViewController_onPageHide)(void* controllerRef);
void (*_Export_ArkUIViewController_onPageShow)(void* controllerRef);
void (*_Export_ArkUIViewController_onSurfaceChanged)(void* controllerRef, libkn_KInt width, libkn_KInt height);
void (*_Export_ArkUIViewController_onSurfaceCreated)(void* controllerRef, void* xcomponentPtr, libkn_KInt width, libkn_KInt height);
void (*_Export_ArkUIViewController_onSurfaceDestroyed)(void* controllerRef);
void (*_Export_ArkUIViewController_onSurfaceHide)(void* controllerRef);
void (*_Export_ArkUIViewController_onSurfaceShow)(void* controllerRef);
libkn_KInt (*_Export_ArkUIViewController_requestSyncRefresh)(void* controllerRef);
const char* (*_Export_ArkUIViewController_sendMessage)(void* controllerRef, const char* type, const char* message);
void (*_Export_ArkUIViewController_setContext)(void* controllerRef, void* context);
void (*_Export_ArkUIViewController_setEnv)(void* controllerRef, void* env);
void (*_Export_ArkUIViewController_setId)(void* controllerRef, const char* id);
void (*_Export_ArkUIViewController_setMessenger)(void* controllerRef, void* messenger);
void (*_Export_ArkUIViewController_setRootView)(void* controllerRef, void* backRootView, void* foreRootView, void* touchableRootView);
void (*_Export_ArkUIViewController_setUIContext)(void* controllerRef, void* uiContext);
void (*_Export_ArkUIViewController_setXComponentRender)(void* controllerRef, void* render);
void (*_Export_ArkUIViewInitializer_init)(void* env, void* exports);
} arkui;
} ui;
} export_;
} compose;
} androidx;
struct { struct {
struct { struct {
struct { struct {
......
#!/bin/bash
# 快速清理脚本 - 直接删除所有生成的文件
TARGET_DIR="composeApp/src/commonMain/kotlin/com/dong/maxhap/HapTestPage"
# 检查目录和文件
if [ ! -d "$TARGET_DIR" ]; then
echo "目录不存在: $TARGET_DIR"
exit 1
fi
FILE_COUNT=$(find "$TARGET_DIR" -name "MaxFile*.kt" -type f | wc -l)
if [ "$FILE_COUNT" -eq 0 ]; then
echo "没有找到MaxFile*.kt文件"
exit 0
fi
echo "开始删除 $FILE_COUNT 个文件..."
# 直接删除文件
find "$TARGET_DIR" -name "MaxFile*.kt" -type f -delete
# 验证删除结果
REMAINING=$(find "$TARGET_DIR" -name "MaxFile*.kt" -type f | wc -l)
if [ "$REMAINING" -eq 0 ]; then
echo "清理完成!已删除 $FILE_COUNT 个文件"
else
echo "删除失败,仍剩余 $REMAINING 个文件"
exit 1
fi
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment