Skip to content

Commit ce8b267

Browse files
Merge pull request #360 from jpush/dev
Dev
2 parents 801881f + 8f4b36f commit ce8b267

File tree

14 files changed

+327
-57
lines changed

14 files changed

+327
-57
lines changed

JPushConfiguration.js

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,24 +51,13 @@ function insertJpushCode(path) {
5151
var rf = fs.readFileSync(path, "utf-8");
5252
var searchDidlaunch = rf.match(/\n.*didFinishLaunchingWithOptions.*\n?\{/);
5353
if (searchDidlaunch == null) {
54-
console.log("没有匹配到 didFinishLaunchingWithOptions");
54+
console.log("没有匹配到 didFinishLaunchingWithOptions,将自动插入改方法");
5555
console.log(rf);
5656
} else {
5757
// console.log(searchDidlaunch[0]);
5858
var oldValue = rf.match(/\[JPUSHService registerForRemoteNotificationTypes/)
5959
if (oldValue == null) {
60-
rf = rf.replace(searchDidlaunch[0], searchDidlaunch[0] + "\n if \(\[\[UIDevice currentDevice\]\.systemVersion floatValue\] >= 10.0\) \{\n \#ifdef NSFoundationVersionNumber_iOS_9_x_Max\n JPUSHRegisterEntity \* entity \= \[\[JPUSHRegisterEntity alloc\] init\]\;\n entity\.types \= UNAuthorizationOptionAlert\|UNAuthorizationOptionBadge\|UNAuthorizationOptionSound\;\n \[JPUSHService registerForRemoteNotificationConfig\:entity delegate\:self\]\;\n \n\#endif\n\} else if \(\[\[UIDevice currentDevice\]\.systemVersion floatValue\] \>\= 8\.0\) \{\n\
61-
\[JPUSHService registerForRemoteNotificationTypes\:\(UIUserNotificationTypeBadge \|\n\
62-
UIUserNotificationTypeSound \|\n\
63-
UIUserNotificationTypeAlert\)\n\
64-
categories\:nil\]\;\n\
65-
\} else \{\n\
66-
\[JPUSHService registerForRemoteNotificationTypes\:\(UIRemoteNotificationTypeBadge \|\n\
67-
UIRemoteNotificationTypeSound \|\n\
68-
UIRemoteNotificationTypeAlert)\n\
69-
categories\:nil\]\;\n\
70-
}\n\
71-
\n\
60+
rf = rf.replace(searchDidlaunch[0], searchDidlaunch[0] + "\nJPUSHRegisterEntity \* entity \= \[\[JPUSHRegisterEntity alloc\] init\]\;\n entity\.types \= UNAuthorizationOptionAlert\|UNAuthorizationOptionBadge\|UNAuthorizationOptionSound\;\n \[JPUSHService registerForRemoteNotificationConfig\:entity delegate\:self\]\;\n\
7261
\[JPUSHService setupWithOption\:launchOptions appKey\:\@\"" + appKey + "\"\n\
7362
channel\:nil apsForProduction\:nil\]\;");
7463
fs.writeFileSync(path, rf, "utf-8");
@@ -82,7 +71,7 @@ function insertJpushCode(path) {
8271
var search = rf.match(/\n.*didRegisterForRemoteNotificationsWithDeviceToken\:\(NSData \*\)deviceToken[ ]*\{/);
8372

8473
if (search == null) {
85-
console.log("没有匹配到 函数 didRegisterForRemoteNotificationsWithDeviceToken");
74+
console.log("没有匹配到 函数 didRegisterForRemoteNotificationsWithDeviceToken,将自动插入改方法");
8675
rf = rf.replace(/\@end/, "\- \(void\)application\:\(UIApplication \*\)application\ didRegisterForRemoteNotificationsWithDeviceToken\:\(NSData \*\)deviceToken \{\n\[JPUSHService registerDeviceToken:deviceToken\]\;\n\}\n\@end");
8776
// console.log(rf);
8877
fs.writeFileSync(path, rf, "utf-8");
@@ -102,7 +91,7 @@ function insertJpushCode(path) {
10291
var rf = fs.readFileSync(path, "utf-8");
10392
var search = rf.match(/\n.*didReceiveRemoteNotification\:\(NSDictionary \*\)userInfo[ ]*\{/);
10493
if (search == null) {
105-
console.log("没有匹配到 函数 didReceiveRemoteNotification");
94+
console.log("没有匹配到 函数 didReceiveRemoteNotification,将自动插入改方法");
10695
rf = rf.replace(/\@end/, "\- \(void\)application\:\(UIApplication \*\)application\ didReceiveRemoteNotification\:\(NSDictionary \*\)userInfo \{\n\[\[NSNotificationCenter\ defaultCenter\]\ postNotificationName\:kJPFDidReceiveRemoteNotification\ object\:userInfo\]\;\n\}\n\@end");
10796
// console.log(rf);
10897
fs.writeFileSync(path, rf, "utf-8");
@@ -112,7 +101,7 @@ function insertJpushCode(path) {
112101
var rf = fs.readFileSync(path, "utf-8");
113102
var search = rf.match(/\n.*didReceiveRemoteNotification\:[ ]*\(NSDictionary \*\)[ ]*userInfo[ ]*fetchCompletionHandler\:\(void[ ]*\(\^\)[ ]*\(UIBackgroundFetchResult\)\)completionHandler \{/);
114103
if (search == null) {
115-
console.log("没有匹配到 函数 didReceiveRemoteNotification fetchCompletionHandler");
104+
console.log("没有匹配到 函数 didReceiveRemoteNotification fetchCompletionHandler,将自动插入改方法");
116105
rf = rf.replace(/\@end/, "\- \(void\)application\:\(UIApplication \*\)application\ didReceiveRemoteNotification\:\(NSDictionary \*\)userInfo fetchCompletionHandler\:\(void\ \(\^\) \(UIBackgroundFetchResult\)\)completionHandler\ \{\n\[\[NSNotificationCenter\ defaultCenter\]\ postNotificationName\:kJPFDidReceiveRemoteNotification\ object\:userInfo\]\;\n\}\n\@end");
117106
// console.log(rf);
118107
fs.writeFileSync(path, rf, "utf-8");
@@ -122,21 +111,28 @@ function insertJpushCode(path) {
122111
var rf = fs.readFileSync(path, "utf-8");
123112
var search = rf.match(/\n.*willPresentNotification\:\(UNNotification \*\)notification[ ]*withCompletionHandler\:.*\{\n/);
124113
if (search == null) {
125-
console.log("没有匹配到 函数 willPresentNotification");
126-
rf = rf.replace(/\@end/, "\- \(void\)jpushNotificationCenter\:\(UNUserNotificationCenter\ \*\)center willPresentNotification\:\(UNNotification\ \*\)notification\ withCompletionHandler\:\(void\ \(\^\)\(NSInteger\)\)completionHandler\ \{\n NSDictionary\ \* userInfo\ \=\ notification\.request\.content\.userInfo\;\n if\(\[notification\.request\.trigger\ isKindOfClass\:\[UNPushNotificationTrigger\ class\]\]\)\ \{\n \[JPUSHService\ handleRemoteNotification\:userInfo\]\;\n \[\[NSNotificationCenter\ defaultCenter\]\ postNotificationName\:kJPFDidReceiveRemoteNotification\ object\:userInfo\]\;\n \ \ \ \}\n completionHandler\(UNNotificationPresentationOptionAlert\)\;\n\}\n\@end");
127-
// console.log(rf);
114+
console.log("没有匹配到 函数 willPresentNotification,将自动插入改方法");
115+
rf = rf.replace(/\@end/, "\- \(void\)jpushNotificationCenter\:\(UNUserNotificationCenter\ \*\)center willPresentNotification\:\(UNNotification\ \*\)notification\ withCompletionHandler\:\(void\ \(\^\)\(NSInteger\)\)completionHandler\ \{\n NSDictionary\ \* userInfo\ \=\ notification\.request\.content\.userInfo\;\n \[JPUSHService\ handleRemoteNotification\:userInfo\]\;\n \[\[NSNotificationCenter\ defaultCenter\]\ postNotificationName\:kJPFDidReceiveRemoteNotification\ object\:userInfo\]\;\n \ \ \ \n completionHandler\(UNNotificationPresentationOptionAlert\)\;\n\}\n\@end");
128116
fs.writeFileSync(path, rf, "utf-8");
129117
}
130118

131119
// 这里插入 didReceiveNotificationResponse
132120
var rf = fs.readFileSync(path, "utf-8");
133121
var search = rf.match(/\n.*jpushNotificationCenter\:\(UNUserNotificationCenter \*\)center[ ]*didReceiveNotificationResponse\:\(UNNotificationResponse\ \*\)response.*\{\n/);
134122
if (search == null) {
135-
console.log("没有匹配到 函数 didReceiveRemoteNotification");
136-
rf = rf.replace(/\@end/, "\- \(void\)jpushNotificationCenter\:\(UNUserNotificationCenter\ \*\)center\ didReceiveNotificationResponse\:\(UNNotificationResponse\ \*\)response\ withCompletionHandler\:\(void\ \(\^\)\(\)\)completionHandler\ \{\nNSDictionary\ \*\ userInfo\ \=\ response\.notification\.request\.content\.userInfo\;\nif\(\[response\.notification\.request\.trigger\ isKindOfClass\:\[UNPushNotificationTrigger\ class\]\]\)\ \{\n\[JPUSHService\ handleRemoteNotification\:userInfo\]\;\n\[\[NSNotificationCenter\ defaultCenter\]\ postNotificationName\:kJPFOpenNotification\ object:userInfo\]\;\n\}\ncompletionHandler\(\)\;\n\}\n\@end");
123+
console.log("没有匹配到 函数 didReceiveRemoteNotification,将自动插入改方法");
124+
rf = rf.replace(/\@end/, "\- \(void\)jpushNotificationCenter\:\(UNUserNotificationCenter\ \*\)center\ didReceiveNotificationResponse\:\(UNNotificationResponse\ \*\)response\ withCompletionHandler\:\(void\ \(\^\)\(\)\)completionHandler\ \{\nNSDictionary\ \*\ userInfo\ \=\ response\.notification\.request\.content\.userInfo\;\n\[JPUSHService\ handleRemoteNotification\:userInfo\]\;\n\[\[NSNotificationCenter\ defaultCenter\]\ postNotificationName\:kJPFOpenNotification\ object:userInfo\]\;\n\ncompletionHandler\(\)\;\n\}\n\@end");
137125
// console.log(rf);
138126
fs.writeFileSync(path, rf, "utf-8");
139127
}
128+
129+
var rf = fs.readFileSync(path, "utf-8");
130+
var search = rf.match(/\n.*didReceiveLocalNotification\:\(UILocalNotification \*\)notification[ ]*\{/);
131+
if (search == null) {
132+
console.log("没有匹配到 函数 didReceiveLocalNotification,将自动插入改方法");
133+
rf = rf.replace(/\@end/, "\- \(void\)application\:\(UIApplication \*\)application\ didReceiveLocalNotification\:\(UILocalNotification \*\)notification \{\n\[\[NSNotificationCenter\ defaultCenter\]\ postNotificationName\:kJPFDidReceiveRemoteNotification\ object\:notification.userInfo\]\;\n\}\n\@end");
134+
fs.writeFileSync(path, rf, "utf-8");
135+
}
140136
}
141137

142138

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,14 @@ dependencies {
8989
v1.6.7 新增 API `jumpToPushActivity`,使用参考 [demo](./example/react-native-android/push_activity.js#L113)
9090

9191

92+
93+
94+
## [常见问题](./example/documents/common_problems)
95+
9296
### [关于更新 RN](https://github.com/jpush/jpush-react-native/blob/master/example/documents/Update%20React%20Native.md)
9397

9498
---
9599
贡献者列表
96100
- [bang88](https://github.com/bang88)
97101
- [pampang](https://github.com/pampang)
102+
- [huhuanming](https://github.com/huhuanming)

android/src/main/java/cn/jpush/reactnativejpush/JPushModule.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
import android.content.Context;
99
import android.content.Intent;
1010
import android.os.Bundle;
11-
import android.text.TextUtils;
12-
import android.widget.Toast;
1311

1412
import com.facebook.react.bridge.Arguments;
1513
import com.facebook.react.bridge.Callback;
@@ -23,8 +21,9 @@
2321
import com.facebook.react.modules.core.DeviceEventManagerModule;
2422

2523

24+
import org.json.JSONObject;
25+
2626
import java.text.SimpleDateFormat;
27-
import java.util.Calendar;
2827
import java.util.Date;
2928
import java.util.HashMap;
3029
import java.util.HashSet;
@@ -36,7 +35,7 @@
3635
import cn.jpush.android.api.CustomPushNotificationBuilder;
3736
import cn.jpush.android.api.JPushInterface;
3837
import cn.jpush.android.api.JPushMessage;
39-
import cn.jpush.android.api.TagAliasCallback;
38+
import cn.jpush.android.data.JPushLocalNotification;
4039
import cn.jpush.android.service.JPushMessageReceiver;
4140

4241
public class JPushModule extends ReactContextBaseJavaModule {
@@ -454,6 +453,31 @@ public void setSilenceTime(ReadableMap map) {
454453
}
455454
}
456455

456+
@ReactMethod
457+
public void sendLocalNotification(ReadableMap map) {
458+
try {
459+
JPushLocalNotification ln = new JPushLocalNotification();
460+
ln.setBuilderId(map.getInt("buildId"));
461+
ln.setNotificationId(map.getInt("id"));
462+
ln.setTitle(map.getString("title"));
463+
ln.setContent(map.getString("content"));
464+
ReadableMap extra = map.getMap("extra");
465+
JSONObject json = new JSONObject();
466+
while (extra.keySetIterator().hasNextKey()) {
467+
String key = extra.keySetIterator().nextKey();
468+
json.put(key, extra.getString(key));
469+
}
470+
ln.setExtras(json.toString());
471+
if (map.hasKey("fireTime")) {
472+
long date = (long) map.getDouble("fireTime");
473+
ln.setBroadcastTime(date);
474+
}
475+
JPushInterface.addLocalNotification(getReactApplicationContext(), ln);
476+
} catch (Exception e) {
477+
e.printStackTrace();
478+
}
479+
}
480+
457481
/**
458482
* 接收自定义消息,通知,通知点击事件等事件的广播
459483
* 文档链接:http://docs.jiguang.cn/client/android_api/

example/documents/Common.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22

33
Common API for Android and iOS.
44

5-
- setTags(array, successCallback, failedCallback)
5+
- setTags(array, successCallback,)
66

77
- getRegistrationID(callback)
88

9-
- setAlias(alias, successCallback, failedCallback)
9+
- setAlias(alias, successCallback)
1010

1111
Note: In Android, you must call initPush first, iOS doesn't need.
1212

13-
14-
1513
**收到打开通知事件**
1614

17-
- addOpenNotificationListener(callback)
15+
**NOTE: **iOS 在 [email protected] 以上版本才提供该方法
16+
17+
- addReceiveOpenNotificationListener(callback)
1818

1919

2020
```
@@ -25,13 +25,14 @@ JPushModule.addReceiveOpenNotificationListener((map) => {
2525
});
2626
```
2727

28-
- removeOpenNotificationListener(event)
29-
28+
- removeReceiveOpenNotificationListener(event)
3029

3130

3231
**收到通知事件**
3332

34-
- addReceiveNotificationListener(callback)
33+
**NOTE: **iOS 在 [email protected] 以上版本才提供该方法
34+
35+
- addReceiveNotificationListener(callback)
3536

3637

3738
```
@@ -43,14 +44,16 @@ JPushModule.addReceiveNotificationListener((map) => {
4344
});
4445
```
4546

46-
- removeReceiveNotificationListener(event)
47+
- removeReceiveNotificationListener(event)
4748

4849

4950

5051

5152
**接收自定义消息**(Add this listener to receive custom message.)
5253

53-
- addReceiveCustomMsgListener(callback)
54+
**NOTE: **iOS 在 [email protected] 以上版本才提供该方法
55+
56+
- addReceiveCustomMsgListener(callback)
5457

5558

5659
- removeReceiveCustomMsgListener(event)
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
## 常见问题
2+
3+
- [事件的解析](#事件的解析)
4+
- [页面跳转](#页面跳转)
5+
- [编译报错](#编译报错)
6+
- [iOS 收不到推送](#iOS收不到推送)
7+
- [iOS 应用角标 Badge](#iOS应用角标Badge)
8+
- [其他](#其他)
9+
10+
11+
12+
### 事件的解析
13+
14+
插件提供几种事件,这里对常见误区进行解释:
15+
16+
#### iOS:
17+
18+
iOS 插件在 2.0.0+ 版本才提供 add********Listener 的方法,如果使用该接口,建议升级到最新版本。
19+
20+
- 收到推送并且点击推送:
21+
22+
- 应用没有启动情况:走 `JPushModule.addOpenNotificationLaunchAppListener` 的回调
23+
24+
- 应用已经启动但是应用在前台:
25+
26+
- iOS 10 及以上的系统:走 `JPushModule.addReceiveOpenNotificationListener` 的回调
27+
28+
- iOS 9 以下的系统:走 `JPushModule.addReceiveNotificationListener` 的回调
29+
- 在前台收到推送:走 `JPushModule.addReceiveNotificationListener` 的回调
30+
- iOS 10 允许推送在前台展示,如果应用在前台且点击了推送,那么还会走 `JPushModule.addReceiveOpenNotificationListener` 回调。
31+
32+
#### Android
33+
- 没有执行 addReceiveOpenNotificationListener 回调。
34+
35+
解决方法: 在监听通知事件前,Android 加入了 `notifiyJSDidLoad` (1.6.6 版本后加入),务必在监听事件前先调用此方法。
36+
37+
38+
39+
### 页面跳转
40+
41+
#### iOS:
42+
43+
应用可以在点击推送事件中直接在 reactJS 中做跳转。
44+
45+
#### Android:
46+
47+
可以在点击推送事件中直接在 JS 中做跳转。也可以跳转到原生界面。第二种情况可以[参考这篇文章的高级应用部分](http://www.jianshu.com/p/6721a0360af9)
48+
49+
50+
51+
### 编译报错
52+
53+
#### iOS:
54+
55+
- 编译报 JCore 相关错误:检查 `jcore-react-native ` 安装了没,一般成功安装并且成功 link 后就能解决该问题。
56+
57+
- 编译报 i386 错误:这种错误一般是使用 iphone5s 以下模拟器报的错误,如果使用模拟器建议使用 iphone 5s 以上的模拟器,整机编译不受印象。
58+
59+
- 编译报 arm64 或者 x86_64 错误:一般是使用模拟器编译 release 导致的,通过真机编译就不会有这个问题,如果实在是想在模拟器上编译 release 可以参考该 [issue](https://github.com/jpush/jpush-react-native/issues/104)
60+
61+
- 编译找不到头文件:在 iOS 工程中如果找不到头文件可能要在 TARGETS-> BUILD SETTINGS -> Search Paths -> Header Search Paths 添加如下路径
62+
63+
```
64+
$(SRCROOT)/../node_modules/jpush-react-native/ios/RCTJPushModule
65+
```
66+
67+
68+
#### Android
69+
70+
- 编译时报错:找不到符号。
71+
72+
解决方法:import 相关类。可手动导入,也可使用 Android Studio 打开项目,然后使用 option + enter 导入相关类。
73+
74+
- 编译时报错:Multiple dex files define
75+
76+
解决方法:可手动删除 jpush , jcore 下的 build 文件夹,然后重新编译。也可以使用 AS 打开项目,然后选择菜单:Build -> Rebuild Project
77+
78+
79+
80+
### iOS 收不到推送
81+
82+
- 确保是在真机上测试,而不是在模拟器
83+
- 自己的应用已经在 Apple developer 给应用配置推送功能,创建推送证书 (并且保证 bundle id 与 Apple developer 上的是一致的)如果之前没有接触过推送证书建议看视频来 👉 [官方集成视频](https://community.jiguang.cn/t/jpush-ios-sdk/4247)
84+
- 能够获取 deviceToken 但是收不到推送, 如果是使用 xcode 8,检查 (Project -> Target -> Capabilities ) Push Notification 选项是否已经点开,如果没有需要点开
85+
86+
87+
88+
89+
### iOS 应用角标 Badge
90+
91+
有两种方式变变应用角标
92+
93+
- 通过服务器下发,服务端 payload 有一个字段 badge 用于设置应用角标,如果客户端收到该条推送应用角标会被设为 badge ,如果想实现应用收到推送 badge 自动 +1 可以让服务端推送时将 badge 设为 "+1"。
94+
95+
- 调用 setBadge 接口也可以改变应用角标,该 api 会设置本地应用的 badge 并且同步极光服务器的 badge 值(收到推送自动加一会依赖于极光服务器的 badge 值)。
96+
97+
推送事件回调参数中,有一个 badge 值,该值就是服务器下发的 badge 值。
98+
99+
100+
101+
### 其他
102+
103+
#### RegistrationID 相关
104+
105+
建议参考这篇博文 [RegistrationID](https://community.jiguang.cn/t/registrationid/3810)
106+
107+
#### 取消弹出 Toast 信息。
108+
109+
解决方法:在加入 JPushPackage 时,将第一个参数设置为 true 即可。第二个参数设置为 true 将不会打印 debug 日志。
110+
111+
112+

example/documents/iOS_API.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ All apis can find in jpush-react-native/index.js.
5050
```
5151

5252
## 事件
53+
**NOTE: **iOS 在 [email protected] 以上版本才提供该方法
54+
5355
**点击推送启动应用事件**
5456

5557
- addOpenNotificationLaunchAppListener(Function)
@@ -69,6 +71,8 @@ All apis can find in jpush-react-native/index.js.
6971

7072
**登录事件**
7173

74+
**NOTE: **iOS 在 jpush-react-native@2.0.0 以上版本才提供该方法
75+
7276

7377
- addnetworkDidLoginListener(Function)
7478

example/ios/PushDemo/AppDelegate.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ - (void)application:(UIApplication *)application didRegisterForRemoteNotificatio
5252
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
5353
[[NSNotificationCenter defaultCenter] postNotificationName:kJPFDidReceiveRemoteNotification object:userInfo];
5454
}
55+
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
56+
[[NSNotificationCenter defaultCenter] postNotificationName:kJPFDidReceiveRemoteNotification object: notification.userInfo];
57+
}
5558
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^) (UIBackgroundFetchResult))completionHandler {
5659
[[NSNotificationCenter defaultCenter] postNotificationName:kJPFDidReceiveRemoteNotification object:userInfo];
5760
}

example/react-native-iOS/localPush_activity.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,26 @@ var LocalPushActivity = React.createClass({
4444
},
4545

4646
addLocationNotification() {
47-
JPushModule.setLocalNotification(this.state.date.getTime(), this.state.textContain, 5, 'dfsa', 'dfaas', null, null);
48-
47+
// setLocalNotification 和 sendLocalNotification 都可以触发本地推送,推荐使用 sendLocalNotification 方法。
48+
var cdate = new Date()
49+
JPushModule.sendLocalNotification(
50+
{
51+
id:5,
52+
title:'haha',
53+
content:'content',
54+
extra:{haha:'haha',lala:'lala'},
55+
fireTime: cdate.getTime() + 3000,
56+
badge: 8,
57+
sound: 'fasdfa',
58+
subtitle: "subtitle",
59+
title: 'title'
60+
}
61+
)
62+
63+
// JPushModule.setLocalNotification(this.state.date.getTime(), this.state.textContain, 5, 'dfsa', 'dfaas', null, null);
64+
65+
66+
4967
},
5068

5169
render() {

0 commit comments

Comments
 (0)