|
|
'use strict';
|
|
|
|
|
|
import ReactNative from 'react-native';
|
|
|
import SeckillService from '../../services/PanicbuyingService';
|
|
|
import Immutable, {Map} from 'immutable';
|
|
|
import PanicbuyingService from '../../services/PanicbuyingService';
|
|
|
|
|
|
const Platform = require('Platform');
|
|
|
const moment = require('moment');
|
|
|
|
|
|
const {
|
|
|
SET_START_TIME,
|
|
|
QUERY_ACTIVITY_REQUEST,
|
|
|
QUERY_ACTIVITY_SUCCESS,
|
|
|
QUERY_ACTIVITY_FAILURE,
|
|
|
|
|
|
QUERY_PRODUCT_LIST_REQUEST,
|
|
|
QUERY_PRODUCT_LIST_SUCCESS,
|
|
|
QUERY_PRODUCT_LIST_FAILURE,
|
|
|
|
|
|
QUERY_PRODUCT_AND_REMIND_LIST_REQUEST,
|
|
|
QUERY_PRODUCT_AND_REMIND_LIST_SUCCESS,
|
|
|
QUERY_PRODUCT_AND_REMIND_LIST_FAILURE,
|
|
|
|
|
|
SHOW_TIP_MESSAGE,
|
|
|
CLEAR_TIP_MESSAGE,
|
|
|
|
|
|
UPDATE_SECKILL_PRODUCT_VO_LIST,
|
|
|
UPDATE_SECKILL_PRODUCT_LIST,
|
|
|
} = require('../../constants/actionTypes').default;
|
|
|
|
|
|
/**
|
|
|
* [时间缺0补0]
|
|
|
*/
|
|
|
const _timeFormat = (tick) => {
|
|
|
return tick < 10 ? `0${tick}` : tick;
|
|
|
};
|
|
|
|
|
|
export function queryActivityRequest() {
|
|
|
return {
|
|
|
type: QUERY_ACTIVITY_REQUEST,
|
|
|
};
|
|
|
}
|
|
|
|
|
|
export function queryActivitySuccess(json) {
|
|
|
return {
|
|
|
type: QUERY_ACTIVITY_SUCCESS,
|
|
|
payload: json
|
|
|
};
|
|
|
}
|
|
|
|
|
|
export function queryActivityFailure(error) {
|
|
|
return {
|
|
|
type: QUERY_ACTIVITY_FAILURE,
|
|
|
payload: error
|
|
|
};
|
|
|
}
|
|
|
|
|
|
export function queryProductListRequest(activity) {
|
|
|
return {
|
|
|
type: QUERY_PRODUCT_LIST_REQUEST,
|
|
|
payload: activity
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function queryProductListSuccess(json) {
|
|
|
return {
|
|
|
type: QUERY_PRODUCT_LIST_SUCCESS,
|
|
|
payload: json
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function queryProductListFailure(error) {
|
|
|
return {
|
|
|
type: QUERY_PRODUCT_LIST_FAILURE,
|
|
|
payload: error
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function queryProductAndRemindListRequest(activity) {
|
|
|
return {
|
|
|
type: QUERY_PRODUCT_AND_REMIND_LIST_REQUEST,
|
|
|
payload: activity
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function queryProductAndRemindListSuccess(json) {
|
|
|
return {
|
|
|
type: QUERY_PRODUCT_AND_REMIND_LIST_SUCCESS,
|
|
|
payload: json
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function queryProductAndRemindListFailure(error) {
|
|
|
return {
|
|
|
type: QUERY_PRODUCT_AND_REMIND_LIST_FAILURE,
|
|
|
payload: error
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function showTipMessage(message) {
|
|
|
return {
|
|
|
type: SHOW_TIP_MESSAGE,
|
|
|
payload: message
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function clearTipMessage() {
|
|
|
return {
|
|
|
type:CLEAR_TIP_MESSAGE,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function updateSecKillProductVoList(json) {
|
|
|
return {
|
|
|
type: UPDATE_SECKILL_PRODUCT_VO_LIST,
|
|
|
payload: json
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function updateSecKillProductList(json) {
|
|
|
return {
|
|
|
type: UPDATE_SECKILL_PRODUCT_LIST,
|
|
|
payload: json
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function setStartTime(startTime) {
|
|
|
startTime = moment(startTime, 'YYYYMMDDHHmmss').unix();
|
|
|
return {
|
|
|
type: SET_START_TIME,
|
|
|
payload: startTime,
|
|
|
};
|
|
|
}
|
|
|
/*
|
|
|
* 秒杀时间栏
|
|
|
*/
|
|
|
export function getSeckillQueryActivity(cid = 0) {
|
|
|
return (dispatch, getState) => {
|
|
|
let {app, panicbuying} = getState();
|
|
|
dispatch(queryActivityRequest());
|
|
|
return new PanicbuyingService(app.host).fetchQueryActivity()
|
|
|
.then(json => {
|
|
|
if (json.secKillProductVoList && json.secKillProductVoList.length) {
|
|
|
let processedTimeInfo = parseActivityTimeList(json, cid);
|
|
|
let queryActivityInfo = processedTimeInfo.newQueryActivityInfo;
|
|
|
let focusActivity = processedTimeInfo.focusActivity;
|
|
|
dispatch(queryActivitySuccess({queryActivityInfo, focusActivity}));
|
|
|
if (Date.now() < focusActivity.startTime) {
|
|
|
dispatch(getSeckillProductRemindList(focusActivity));
|
|
|
} else {
|
|
|
dispatch(getSeckillProductList(focusActivity));
|
|
|
}
|
|
|
} else {
|
|
|
dispatch(queryActivityFailure({error:'来晚啦~秒杀已结束'}));
|
|
|
}
|
|
|
})
|
|
|
.catch(error => {
|
|
|
dispatch(queryActivityFailure(error));
|
|
|
dispatch(showTipMessage(error.message));
|
|
|
});
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* 秒杀商品列表
|
|
|
*/
|
|
|
export function getSeckillProductList(activity) {
|
|
|
return (dispatch, getState) => {
|
|
|
let {app, panicbuying} = getState();
|
|
|
let {queryRemindList, queryProductList, curActivity} = panicbuying;
|
|
|
if (!activity) {
|
|
|
activity = curActivity.toJS();
|
|
|
}
|
|
|
dispatch(queryProductListRequest(activity));
|
|
|
queryRemindList = queryRemindList.toJS();
|
|
|
return new PanicbuyingService(app.host).fetchQueryProductList(activity.activityId)
|
|
|
.then(json => {
|
|
|
let productList = [];
|
|
|
if (queryRemindList && queryRemindList.length > 0) {
|
|
|
productList = productAddFlag(json, queryRemindList);
|
|
|
} else {
|
|
|
productList = productAddFlag(json);
|
|
|
}
|
|
|
queryProductList = queryProductList.toJS();
|
|
|
queryProductList[activity.activityId] = productList;
|
|
|
dispatch(queryProductListSuccess(queryProductList));
|
|
|
})
|
|
|
.catch(error => {
|
|
|
dispatch(queryProductListFailure(error));
|
|
|
});
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* 秒杀商品列表
|
|
|
*/
|
|
|
export function getSeckillProductRemindList(activity) {
|
|
|
return (dispatch, getState) => {
|
|
|
let queryProductRemindList = (activity, uid) => {
|
|
|
dispatch(queryProductAndRemindListRequest(activity));
|
|
|
let {app, panicbuying} = getState();
|
|
|
let {queryProductList} = panicbuying;
|
|
|
Promise.all([
|
|
|
new PanicbuyingService(app.host).fetchQueryProductList(activity.activityId),
|
|
|
new PanicbuyingService(app.host).fetchQueryRemindList(activity.activityId, uid),
|
|
|
]).then(result => {
|
|
|
let productList = result[0];
|
|
|
let remindList = result[1];
|
|
|
productList = productAddFlag(productList, remindList);
|
|
|
queryProductList = queryProductList.toJS();
|
|
|
queryProductList[activity.activityId] = productList;
|
|
|
dispatch(queryProductAndRemindListSuccess({queryProductList,remindList}));
|
|
|
|
|
|
})
|
|
|
.catch(error => {
|
|
|
dispatch(queryProductAndRemindListFailure(error));
|
|
|
});
|
|
|
}
|
|
|
|
|
|
ReactNative.NativeModules.YH_CommonHelper.uid()
|
|
|
.then(uid => {
|
|
|
queryProductRemindList(activity, uid);
|
|
|
})
|
|
|
.catch(error => {
|
|
|
dispatch(getSeckillProductList(activity));
|
|
|
});
|
|
|
};
|
|
|
}
|
|
|
|
|
|
export function addCancelUserReminder(method='app.seckill.addUserReminder', activityId=0, productSkn=0, uid=0, secKillId=0, okTip='', failTip='') {
|
|
|
return (dispatch, getState) => {
|
|
|
let {app, panicbuying} = getState();
|
|
|
let {queryProductList, curActivity} = panicbuying;
|
|
|
dispatch(clearTipMessage());
|
|
|
return new PanicbuyingService(app.host).addCancelUserReminder(method,activityId,productSkn,uid,secKillId)
|
|
|
.then(json => {
|
|
|
//更新提醒状态
|
|
|
let remindFlag;
|
|
|
if (method === 'app.seckill.addUserReminder') {
|
|
|
remindFlag = true;
|
|
|
} else {
|
|
|
remindFlag = false;
|
|
|
}
|
|
|
queryProductList = queryProductList.toJS();
|
|
|
let curActivity = {};
|
|
|
queryProductList[activityId].forEach((productItem, i) => {
|
|
|
if (productItem.id === secKillId) {
|
|
|
productItem.remindFlag = remindFlag;
|
|
|
}
|
|
|
});
|
|
|
dispatch(showTipMessage(okTip));
|
|
|
dispatch(updateSecKillProductList(queryProductList));
|
|
|
})
|
|
|
.catch(error => {
|
|
|
dispatch(showTipMessage(failTip));
|
|
|
});
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
export function clickActivityTimeItem(activity) {
|
|
|
return (dispatch, getState) => {
|
|
|
let {app, panicbuying} = getState();
|
|
|
let {queryActivityInfo} = panicbuying;
|
|
|
queryActivityInfo = queryActivityInfo.toJS();
|
|
|
let curActivity = activity;
|
|
|
queryActivityInfo.secKillProductVoList.forEach((activityTimeItem, i) => {
|
|
|
if (activityTimeItem.activityId === activity.activityId) {
|
|
|
curActivity = activityTimeItem;
|
|
|
activityTimeItem.focus = true;
|
|
|
} else {
|
|
|
activityTimeItem.focus = false;
|
|
|
}
|
|
|
});
|
|
|
let secKillProductVoList = queryActivityInfo.secKillProductVoList;
|
|
|
dispatch(updateSecKillProductVoList({secKillProductVoList, curActivity}));
|
|
|
};
|
|
|
}
|
|
|
|
|
|
export function clickProductItem(product) {
|
|
|
return (dispatch, getState) => {
|
|
|
if (!product.secKillSku || product.secKillSku.length == 0) {
|
|
|
return;
|
|
|
}
|
|
|
let skn = product.secKillSku[0].productSkn;
|
|
|
//
|
|
|
let url = `http://m.yohobuy.com?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":"${skn}", "is_seckill": "Y","tags_filter":"","from_page_name":"${Platform.OS === 'ios'?'iFP_Seckill':'aFP_Seckill'}"}}`;
|
|
|
ReactNative.NativeModules.YH_CommonHelper.jumpWithUrl(url);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function clickRemindBtn(product) {
|
|
|
return (dispatch, getState) => {
|
|
|
ReactNative.NativeModules.YH_CommonHelper.uid()
|
|
|
.then(uid => {
|
|
|
queryRemindList(uid);
|
|
|
})
|
|
|
.catch(error => {
|
|
|
ReactNative.NativeModules.YH_CommonHelper.login()
|
|
|
.then(uid => {
|
|
|
dispatch(clickActivityTimeItem(product));
|
|
|
queryRemindList(uid);
|
|
|
})
|
|
|
.catch(error => {
|
|
|
|
|
|
});
|
|
|
});
|
|
|
|
|
|
|
|
|
let queryRemindList = (uid) => {
|
|
|
let {app, panicbuying} = getState();
|
|
|
let {queryProductList} = panicbuying;
|
|
|
if (!product.secKillSku || product.secKillSku.length == 0) {
|
|
|
return;
|
|
|
}
|
|
|
let skn = product.secKillSku[0].productSkn;
|
|
|
let actionName,
|
|
|
action,
|
|
|
params,
|
|
|
on_off,
|
|
|
method;
|
|
|
let okTip,
|
|
|
failTip,
|
|
|
result;
|
|
|
// default
|
|
|
on_off = true;
|
|
|
action = 'go.addSecKill';
|
|
|
method = 'app.seckill.addUserReminder';
|
|
|
params = {
|
|
|
skn: skn,
|
|
|
startTime: product.startTime,
|
|
|
productName: product.productName,
|
|
|
};
|
|
|
okTip = '设置提醒成功,将在开抢3分钟前提醒';
|
|
|
failTip = '设置提醒失败';
|
|
|
|
|
|
if (product.remindFlag) {
|
|
|
on_off = false;
|
|
|
action = 'go.delSecKill';
|
|
|
okTip = '取消提醒成功';
|
|
|
failTip = '取消提醒失败';
|
|
|
method = 'app.seckill.cancelUserReminder';
|
|
|
}
|
|
|
|
|
|
ReactNative.NativeModules.YH_PanicBuyingHelper.remindTip({
|
|
|
method: action,
|
|
|
arguments: params,
|
|
|
})
|
|
|
.then(flag => { //成功
|
|
|
dispatch(addCancelUserReminder(method, product.activityId, skn,uid, product.id, okTip, failTip));
|
|
|
})
|
|
|
.catch(error => {
|
|
|
dispatch(showTipMessage('请到设置中开启日历授权'));
|
|
|
});
|
|
|
};
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function refreshList() {
|
|
|
return (dispatch, getState) => {
|
|
|
let {app, panicbuying} = getState();
|
|
|
let {queryActivityInfo,queryProductList,curActivity} = panicbuying;
|
|
|
if (curActivity.get('activityId') !== 0 && queryActivityInfo.secKillProductVoList && queryActivityInfo.secKillProductVoList.size > 0) {
|
|
|
queryActivityInfo.secKillProductVoList.forEach((activityInfo, i) => {
|
|
|
if (activityInfo.get('activityId') === curActivity.get('activityId')) {
|
|
|
// dispatch(getSeckillQueryActivity(activityInfo.get('startTime')/1000));
|
|
|
dispatch(getSeckillQueryActivity(activityInfo.get('id')));
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
dispatch(getSeckillQueryActivity());
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 秒杀商品 添加 自定义属性
|
|
|
* ----------------------------------------
|
|
|
* 已开抢
|
|
|
* product.over [APP,H5: 1.已抢光 2.过了endTime]
|
|
|
* product.isSeckill [APP,H5 秒杀中, 与over互斥]
|
|
|
* 抢购中:
|
|
|
* product.over
|
|
|
* product.isSeckill
|
|
|
* 即将开抢:
|
|
|
* product.wait = true
|
|
|
* product.remindFlag = true [APP: 已添加提醒]
|
|
|
* product.remindFalg = false [APP: 默认提醒状态]
|
|
|
* Product.hideRemind = true [APP: queryRemindList接口失败的情况下]
|
|
|
* Product.specialState = 0 1,明天开抢 2.2天后开抢
|
|
|
*/
|
|
|
function productAddFlag(productList, remindList) {
|
|
|
let now = Date.now();
|
|
|
|
|
|
productList
|
|
|
// .sort((a, b) => b.orderBy - a.orderBy)
|
|
|
.forEach(product => {
|
|
|
let startTime = product.startTime * 1000; // s to ms
|
|
|
let endTime = product.endTime * 1000;
|
|
|
|
|
|
product.remindFlag = false;
|
|
|
product.readableTime = moment.unix(product.startTime).format('MM月DD日 HH:mm');
|
|
|
|
|
|
if (now < startTime) { // 未开抢
|
|
|
product.wait = true;
|
|
|
product.isSeckill = true;
|
|
|
|
|
|
if (!remindList) {
|
|
|
product.hideRemind = true;
|
|
|
} else if (remindList.length) {
|
|
|
for (let i = 0, j = remindList.length; i < j; i++) {
|
|
|
if (remindList[i].productSkn === product.productSkn) { // remind on;
|
|
|
product.remindFlag = true;
|
|
|
remindList.splice(i, 1);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} else if (product.secKillStatus === 0 || (now > endTime)) { // 确实已抢光, 过了秒杀时间
|
|
|
product.over = true;
|
|
|
}
|
|
|
});
|
|
|
return productList;
|
|
|
}
|
|
|
|
|
|
|
|
|
function parseActivityTimeList(json, cid=0) {
|
|
|
let currentTime = json && json.currentTime ? json.currentTime * 1000 : Date.new();
|
|
|
let secKillProductVoList = json && json.secKillProductVoList ? json.secKillProductVoList : [];
|
|
|
let newActivityTimeList = [];
|
|
|
let focusIndex = false;
|
|
|
// newActivityTimeList = secKillProductVoList.sort((a,b) => a.startTime - b.startTime);// orderBy startTime ASC
|
|
|
newActivityTimeList = secKillProductVoList;
|
|
|
|
|
|
if (cid) {
|
|
|
focusIndex = newActivityTimeList.findIndex(activityTimeItem=> activityTimeItem.id === cid);
|
|
|
|
|
|
if (focusIndex !== -1) {
|
|
|
newActivityTimeList[focusIndex].focus = true;
|
|
|
focusIndex = true;
|
|
|
} else {
|
|
|
focusIndex = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
let now = new Date();
|
|
|
|
|
|
newActivityTimeList.forEach((activityTimeItem, i) => {
|
|
|
let date,
|
|
|
hour = 0,
|
|
|
minute = 0;
|
|
|
|
|
|
activityTimeItem.startTime *= 1000;
|
|
|
activityTimeItem.endTime *= 1000;
|
|
|
activityTimeItem.index = i;
|
|
|
date = new Date(activityTimeItem.startTime);
|
|
|
hour = date.getHours();
|
|
|
minute = date.getMinutes();
|
|
|
activityTimeItem.time = `${_timeFormat(hour)}:${_timeFormat(minute)}`;
|
|
|
|
|
|
let title = (date.getMonth()+1) + '月' + date.getDate() + '日';
|
|
|
activityTimeItem.activityDate = activityTimeItem.tab ? activityTimeItem.tab : title;
|
|
|
activityTimeItem.activityHour = hour;
|
|
|
|
|
|
activityTimeItem.specialState = 0;
|
|
|
|
|
|
let offsetDate = getDiffDays(date, now);
|
|
|
activityTimeItem.specialState = offsetDate < 0 ? 0 : offsetDate;
|
|
|
|
|
|
if (currentTime > activityTimeItem.startTime) {
|
|
|
|
|
|
if(currentTime > activityTimeItem.endTime){
|
|
|
activityTimeItem.over = true;
|
|
|
}else{
|
|
|
activityTimeItem.now = true;
|
|
|
// focusIndex || (activityTimeItem.focus = focusIndex = true);
|
|
|
}
|
|
|
} else {
|
|
|
activityTimeItem.wait = true;
|
|
|
}
|
|
|
});
|
|
|
if (newActivityTimeList.length && newActivityTimeList.findIndex(activityTimeItem => activityTimeItem.focus) < 0) {
|
|
|
// 默认focus第一个
|
|
|
newActivityTimeList[0].focus = true;
|
|
|
}
|
|
|
|
|
|
let focusActivity = newActivityTimeList.find(activityTimeItem => activityTimeItem.focus);
|
|
|
let newQueryActivityInfo = {
|
|
|
currentTime:currentTime,
|
|
|
secKillProductVoList: newActivityTimeList,
|
|
|
}
|
|
|
return {
|
|
|
newQueryActivityInfo,
|
|
|
focusActivity,
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
//date1 减去 date2 相差的天数
|
|
|
function getDiffDays(date1, date2){
|
|
|
let nDate1 = new Date();
|
|
|
nDate1 = new Date(date1.getFullYear(),date1.getMonth(),date1.getDate());
|
|
|
let newDate2 = new Date(date2);
|
|
|
newDate2 =new Date(date2.getFullYear(),date2.getMonth(),date2.getDate());
|
|
|
let diffDays = (nDate1 - newDate2) / 1000 / 60 / 60 / 24;
|
|
|
return diffDays;
|
|
|
}
|
|
|
|
|
|
export function updateStatusProductList(activity) {
|
|
|
return (dispatch, getState) => {
|
|
|
let {app, panicbuying} = getState();
|
|
|
let {queryRemindList, queryProductList, curActivity, localServerTimeDiff} = panicbuying;
|
|
|
if (!activity) {
|
|
|
activity = curActivity.toJS();
|
|
|
}
|
|
|
|
|
|
queryProductList = queryProductList.toJS();
|
|
|
let productList = queryProductList[activity.activityId];
|
|
|
|
|
|
productList && productList.forEach((product, i) => {
|
|
|
let nowServerTime = Date.now() + localServerTimeDiff;
|
|
|
let startTime = product.startTime * 1000; // s to ms
|
|
|
let endTime = product.endTime * 1000;
|
|
|
|
|
|
if (nowServerTime < startTime) { // 未开抢
|
|
|
product.wait = true;
|
|
|
product.over = false;
|
|
|
// product.now = false;
|
|
|
} else if (nowServerTime > startTime && nowServerTime < endTime) {
|
|
|
product.wait = false;
|
|
|
// product.now = true;
|
|
|
product.over = false;
|
|
|
} else if (product.secKillStatus === 0 || (nowServerTime > endTime)) { // 确实已抢光, 过了秒杀时间
|
|
|
product.wait = false;
|
|
|
// product.now = false;
|
|
|
product.over = true;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
dispatch(updateSecKillProductList(queryProductList));
|
|
|
};
|
|
|
}
|
|
|
|
|
|
export function updateStatusCurActivity() {
|
|
|
return (dispatch, getState) => {
|
|
|
let {app, panicbuying} = getState();
|
|
|
let {queryRemindList, queryActivityInfo, curActivity, localServerTimeDiff} = panicbuying;
|
|
|
|
|
|
curActivity = curActivity.toJS();
|
|
|
let t = Date.now();
|
|
|
let nowServerTime = Date.now() + localServerTimeDiff;
|
|
|
let startTime = curActivity.startTime;
|
|
|
let endTime = curActivity.endTime;
|
|
|
|
|
|
if (nowServerTime < startTime) {
|
|
|
curActivity.wait = true;
|
|
|
curActivity.now = false;
|
|
|
curActivity.over = false;
|
|
|
} else if (nowServerTime > startTime && nowServerTime < endTime) {
|
|
|
curActivity.wait = false;
|
|
|
curActivity.now = true;
|
|
|
curActivity.over = false;
|
|
|
} else {
|
|
|
curActivity.wait = false;
|
|
|
curActivity.now = false;
|
|
|
curActivity.over = true;
|
|
|
}
|
|
|
let secKillProductVoList = queryActivityInfo.secKillProductVoList;
|
|
|
dispatch(updateSecKillProductVoList({secKillProductVoList, curActivity}));
|
|
|
|
|
|
};
|
|
|
} |
|
|
\ No newline at end of file |
...
|
...
|
|