|
|
|
@ -1,10 +1,8 @@ |
|
|
|
import { _decorator, Component, find, isValid, Label, Node, sp, Tween, tween } from 'cc'; |
|
|
|
import { _decorator, Component, Label, Node, Tween, tween } from 'cc'; |
|
|
|
import { SpriteLoad } from '../../mx/components/SpriteLoad'; |
|
|
|
import { GBundle } from '../game/ConfigRes'; |
|
|
|
import { GBundle, GPath } from '../game/ConfigRes'; |
|
|
|
|
|
|
|
import { TetriType } from '../game/ConfigProjectData'; |
|
|
|
import { TetriType } from '../game/ConfigProjectData'; |
|
|
|
import { tetriNode } from './tetriNode'; |
|
|
|
import { tetriNode } from './tetriNode'; |
|
|
|
import { role } from './role'; |
|
|
|
const { ccclass } = _decorator; |
|
|
|
const { ccclass, property } = _decorator; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**方块功能脚本不是战斗类型的方块 |
|
|
|
/**方块功能脚本不是战斗类型的方块 |
|
|
|
* TetriType == 3 每秒给一个金币 |
|
|
|
* TetriType == 3 每秒给一个金币 |
|
|
|
@ -13,14 +11,15 @@ const { ccclass, property } = _decorator; |
|
|
|
@ccclass('tetriAbility') |
|
|
|
@ccclass('tetriAbility') |
|
|
|
export class tetriAbility extends Component { |
|
|
|
export class tetriAbility extends Component { |
|
|
|
|
|
|
|
|
|
|
|
roleConfig = [ |
|
|
|
/** 旧版:飘字挂在「角色」local(0,50)→(0,150),角色带 mainPosi 与 scale */ |
|
|
|
{id:1, name:"Tetris_coin_1", mainPosi:{x:-2.225,y:-19.558},animSkin:'小黄',scalex:-0.25, scaley:0.25 }, |
|
|
|
private static readonly ICON_PREFAB_SCALE = 4; |
|
|
|
{id:2, name:"Tetris_heal_1", mainPosi:{x:-1.523,y:-8.577},animSkin:'小绿',scalex:-0.15, scaley:0.15 }, |
|
|
|
private static readonly ICON_FLOAT_START_Y = 50; |
|
|
|
{id:3, name:"Tetris_heal_2", mainPosi:{x:-0.473,y:-10.624},animSkin:'小绿',scalex:-0.15, scaley:0.15 }, |
|
|
|
private static readonly ICON_FLOAT_END_Y = 150; |
|
|
|
|
|
|
|
private static readonly ICON_LAYOUT: Record<string, { scaleX: number; scaleY: number; mainPosi: { x: number; y: number } }> = { |
|
|
|
] |
|
|
|
Tetris_coin_1: { scaleX: -0.25, scaleY: 0.25, mainPosi: { x: -2.225, y: -19.558 } }, |
|
|
|
|
|
|
|
Tetris_heal_1: { scaleX: -0.15, scaleY: 0.15, mainPosi: { x: -1.523, y: -8.577 } }, |
|
|
|
|
|
|
|
Tetris_heal_2: { scaleX: -0.15, scaleY: 0.15, mainPosi: { x: -0.473, y: -10.624 } }, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
private _config: ITableBattleCube | null = null; |
|
|
|
private _config: ITableBattleCube | null = null; |
|
|
|
private _curentWeaponId: number = 0; |
|
|
|
private _curentWeaponId: number = 0; |
|
|
|
@ -30,254 +29,123 @@ export class tetriAbility extends Component { |
|
|
|
|
|
|
|
|
|
|
|
addValue = 0 |
|
|
|
addValue = 0 |
|
|
|
|
|
|
|
|
|
|
|
roleNode: Node = null; |
|
|
|
setConfig(config: ITableBattleCube) { |
|
|
|
weaponNode: Node = null; |
|
|
|
|
|
|
|
/** 异步创建角色进行中,防止 setConfig/start 并发各拉一个 */ |
|
|
|
|
|
|
|
private _roleCreating = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setConfig(config: ITableBattleCube){ |
|
|
|
|
|
|
|
this._config = config |
|
|
|
this._config = config |
|
|
|
this._curentWeaponId = config.weaponid |
|
|
|
this._curentWeaponId = config.weaponid |
|
|
|
this.addRole() |
|
|
|
this._removeLegacyRoleNodes() |
|
|
|
|
|
|
|
this.setView() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
start() { |
|
|
|
start() { |
|
|
|
//功能方块:setConfig 通常已调过 addRole;此处兜底,靠 inflight/roleNode 防重
|
|
|
|
this._removeLegacyRoleNodes() |
|
|
|
this.addRole() |
|
|
|
if (this._config) { |
|
|
|
} |
|
|
|
this.setView() |
|
|
|
private safePutPoolNode(n: Node | null): void { |
|
|
|
|
|
|
|
if (!n) return; |
|
|
|
|
|
|
|
if (!isValid(n)) return; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
if (n.parent) n.destroy(); |
|
|
|
|
|
|
|
//gg.res.putNode(n);
|
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
console.warn('[tetriWeaponCarrier] safePutPoolNode failed', e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
onDestroy(): boolean { |
|
|
|
|
|
|
|
gg.game?.CurentBattle?.pruneDetachedBattleLayers?.(this.node); |
|
|
|
|
|
|
|
const role = this.roleNode; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.roleNode = null; |
|
|
|
|
|
|
|
this._roleCreating = false; |
|
|
|
|
|
|
|
// 武器挂在「角色/武器」下,先回收武器再回收角色,避免子随父一起进半销毁态
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.safePutPoolNode(role); |
|
|
|
|
|
|
|
return true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
addRole(){ |
|
|
|
|
|
|
|
if(this.roleNode || this._roleCreating){ |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if(!this._config){ |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// instantiate / 拷贝可能已带「角色」;清掉多余的,避免叠两个
|
|
|
|
|
|
|
|
let existingRole: Node | null = null; |
|
|
|
|
|
|
|
for (let i = 0; i < this.node.children.length; i++) { |
|
|
|
|
|
|
|
const c = this.node.children[i]; |
|
|
|
|
|
|
|
if (c.name !== '角色') continue; |
|
|
|
|
|
|
|
if (!existingRole) existingRole = c; |
|
|
|
|
|
|
|
else if (c?.isValid) c.destroy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (existingRole?.isValid) { |
|
|
|
|
|
|
|
this._setupRoleNode(existingRole); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
this._roleCreating = true; |
|
|
|
|
|
|
|
void gg.res.getNodeAsync('角色/', '角色', GBundle.tetriCards).then((roleNode) => { |
|
|
|
|
|
|
|
this._roleCreating = false; |
|
|
|
|
|
|
|
if(!roleNode?.isValid || !this.node?.isValid){ |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 并发回调晚到:已有角色则销毁多余实例
|
|
|
|
|
|
|
|
if (this.roleNode?.isValid) { |
|
|
|
|
|
|
|
this.safePutPoolNode(roleNode); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this._setupRoleNode(roleNode); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private _setupRoleNode(roleNode: Node) { |
|
|
|
/** 旧版会在方块下挂「角色」预制体;现改为方块 spine 表情,不再创建 */ |
|
|
|
this.roleNode = roleNode |
|
|
|
private _removeLegacyRoleNodes(): void { |
|
|
|
roleNode.setParent(this.node) |
|
|
|
if (!this.node?.isValid) return; |
|
|
|
roleNode.active = true |
|
|
|
const kids = this.node.children.slice(); |
|
|
|
let conf = this.roleConfig.find(item => item.name == this._config.cubename) |
|
|
|
for (const ch of kids) { |
|
|
|
if(conf){ |
|
|
|
if (ch?.isValid && ch.name === '角色') { |
|
|
|
roleNode.setPosition(conf.mainPosi.x, conf.mainPosi.y) |
|
|
|
ch.destroy(); |
|
|
|
roleNode.setScale(conf.scalex, conf.scaley) |
|
|
|
|
|
|
|
const anim = roleNode.getChildByName('anim'); |
|
|
|
|
|
|
|
const animSk = anim?.getComponent(sp.Skeleton); |
|
|
|
|
|
|
|
if (animSk) { |
|
|
|
|
|
|
|
animSk.setSkin(conf.animSkin); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 产币/回血改用方块根节点 spine 三态表情;旧「角色/anim」仅产效时短暂播放
|
|
|
|
|
|
|
|
if (anim?.isValid) { |
|
|
|
|
|
|
|
anim.active = false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const roleComp = roleNode.getComponent(role); |
|
|
|
|
|
|
|
roleComp.setFollowTarget(this.node); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.scheduleOnce(()=>{ |
|
|
|
|
|
|
|
this.setView() |
|
|
|
|
|
|
|
},0.1) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setView(){ |
|
|
|
setView() { |
|
|
|
let conf = gg.data.project.getWeaponData(this._curentWeaponId) |
|
|
|
let conf = gg.data.project.getWeaponData(this._curentWeaponId) |
|
|
|
//console.log('tetriAbility conf',conf)
|
|
|
|
if (!conf) { |
|
|
|
if(!conf){ |
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
this.cdTime = conf.cd |
|
|
|
this.cdTime = conf.cd |
|
|
|
this.cdTimeFix = conf.cd |
|
|
|
this.cdTimeFix = conf.cd |
|
|
|
//获取武器等级系数
|
|
|
|
|
|
|
|
let weaponLevel = gg.data.project.getWeaponLevel(conf.id); |
|
|
|
let weaponLevel = gg.data.project.getWeaponLevel(conf.id); |
|
|
|
let levelPara = gg.data.project.getLevelParaByWeaponLevel(weaponLevel, conf.id) |
|
|
|
let levelPara = gg.data.project.getLevelParaByWeaponLevel(weaponLevel, conf.id) |
|
|
|
let weapon_para = conf.weapon_para |
|
|
|
let weapon_para = conf.weapon_para |
|
|
|
|
|
|
|
|
|
|
|
this.addValue = Math.floor(weapon_para * levelPara) |
|
|
|
this.addValue = Math.floor(weapon_para * levelPara) |
|
|
|
this.changeIcon(conf.typeicon) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log('tetriAbility addValue',this.addValue) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 挂到方块根节点时,用锚点复刻旧版「角色」→飘字层级(prefab scale=4 由角色 scale 缩小) */ |
|
|
|
|
|
|
|
private _setupFloatingIcon(iconNode: Node, addNum: number): void { |
|
|
|
|
|
|
|
const layout = tetriAbility.ICON_LAYOUT[this._config?.cubename ?? ''] |
|
|
|
|
|
|
|
?? { scaleX: -0.25, scaleY: 0.25, mainPosi: { x: 0, y: 0 } }; |
|
|
|
|
|
|
|
|
|
|
|
changeWeapon(weaponani){ |
|
|
|
Tween.stopAllByTarget(iconNode); |
|
|
|
return |
|
|
|
|
|
|
|
// if(this.weaponNode){
|
|
|
|
|
|
|
|
// gg.res.putNode(this.weaponNode)
|
|
|
|
|
|
|
|
// this.weaponNode = null
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// this.addWeapon(weaponani)
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// //增加武器和修改icon图片
|
|
|
|
|
|
|
|
// addWeapon(weaponani){
|
|
|
|
|
|
|
|
// //创建武器
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// let anim = find('角色/anim', this.node)
|
|
|
|
const anchor = new Node('__floatIconAnchor'); |
|
|
|
// let wuqiNode = find('角色/武器', this.node)
|
|
|
|
anchor.setParent(this.node); |
|
|
|
// let weaponNode = gg.res.getNode('prefab/', weaponani, GBundle.tetriWeapon)
|
|
|
|
anchor.setPosition(layout.mainPosi.x, layout.mainPosi.y, 0); |
|
|
|
// this.weaponNode = weaponNode
|
|
|
|
anchor.setScale(layout.scaleX, layout.scaleY, 1); |
|
|
|
// weaponNode.setParent(wuqiNode)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// anim.getComponent(sp.Skeleton).setAnimation(0, '待机', true)
|
|
|
|
iconNode.setParent(anchor); |
|
|
|
// weaponNode.getComponent(sp.Skeleton).setAnimation(0, '待机', true)
|
|
|
|
iconNode.active = true; |
|
|
|
// }
|
|
|
|
iconNode.setScale(tetriAbility.ICON_PREFAB_SCALE, tetriAbility.ICON_PREFAB_SCALE, 1); |
|
|
|
|
|
|
|
iconNode.setPosition(0, tetriAbility.ICON_FLOAT_START_Y, 0); |
|
|
|
|
|
|
|
iconNode.opacity = 100; |
|
|
|
|
|
|
|
|
|
|
|
changeIcon(typeicon){ |
|
|
|
const labNode = iconNode.getChildByName('lab'); |
|
|
|
|
|
|
|
// prefab 默认 scaleX=-1,配合 anchor 负 scaleX,文字方向与旧版一致
|
|
|
|
|
|
|
|
labNode?.setScale(-1, 1, 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const lab = labNode?.getComponent(Label); |
|
|
|
|
|
|
|
if (lab) { |
|
|
|
|
|
|
|
lab.string = '+' + addNum.toString(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tween(iconNode) |
|
|
|
|
|
|
|
.to(0.5, { y: tetriAbility.ICON_FLOAT_END_Y, opacity: 255 }) |
|
|
|
|
|
|
|
.call(() => { |
|
|
|
|
|
|
|
Tween.stopAllByTarget(iconNode); |
|
|
|
|
|
|
|
if (iconNode?.isValid) { |
|
|
|
|
|
|
|
labNode?.setScale(-1, 1, 1); |
|
|
|
|
|
|
|
iconNode.setScale(tetriAbility.ICON_PREFAB_SCALE, tetriAbility.ICON_PREFAB_SCALE, 1); |
|
|
|
|
|
|
|
gg.res.putNode(iconNode); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (anchor?.isValid) { |
|
|
|
|
|
|
|
anchor.destroy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.start(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
update(deltaTime: number) { |
|
|
|
update(deltaTime: number) { |
|
|
|
//
|
|
|
|
if (!this._config) return; |
|
|
|
//
|
|
|
|
if (!this.node.getComponent(tetriNode)?.isSettled) { |
|
|
|
if(!this.roleNode){ |
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(!this.node.getComponent(tetriNode)?.isSettled){ |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!gg.game?.CurentBattle?.canUpdateFrame() && !gg.game?.CurentBattle?.IsWarnTimeActive) return; |
|
|
|
if (!gg.game?.CurentBattle?.canUpdateFrame() && !gg.game?.CurentBattle?.IsWarnTimeActive) return; |
|
|
|
this.cdTime+=deltaTime*gg.game.CurentBattle.TimeScale |
|
|
|
this.cdTime += deltaTime * gg.game.CurentBattle.TimeScale |
|
|
|
if(this.cdTime >= this.cdTimeFix){ |
|
|
|
if (this.cdTime >= this.cdTimeFix) { |
|
|
|
this.cdTime = 0 |
|
|
|
this.cdTime = 0 |
|
|
|
this.addValueFunc() |
|
|
|
this.addValueFunc() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
addValueFunc() { |
|
|
|
addValueFunc(){ |
|
|
|
if (!this._config) return; |
|
|
|
|
|
|
|
if (!this.node.getComponent(tetriNode)?.isSettled) { |
|
|
|
//没有放稳不生效
|
|
|
|
|
|
|
|
if(!this.node.getComponent(tetriNode)?.isSettled){ |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if(!this.roleNode){ |
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
if(!this.roleNode.isValid){ |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
let anim = find('anim', this.roleNode) |
|
|
|
|
|
|
|
if (!anim?.isValid) return; |
|
|
|
|
|
|
|
anim.active = true; |
|
|
|
|
|
|
|
anim.getComponent(sp.Skeleton).setAnimation(0, '攻击', false) |
|
|
|
|
|
|
|
this.scheduleOnce(()=>{ |
|
|
|
|
|
|
|
if (!anim?.isValid) return; |
|
|
|
|
|
|
|
anim.getComponent(sp.Skeleton).setAnimation(0, '待机', true) |
|
|
|
|
|
|
|
anim.active = false; |
|
|
|
|
|
|
|
},1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let getNodeLevel = this.node.getComponent(tetriNode)?.getNodeLevel() || 1 |
|
|
|
let getNodeLevel = this.node.getComponent(tetriNode)?.getNodeLevel() || 1 |
|
|
|
let addNum = this.addValue * getNodeLevel; |
|
|
|
let addNum = this.addValue * getNodeLevel; |
|
|
|
|
|
|
|
|
|
|
|
if(this._config.type == TetriType.Tetris_BaseGold){ |
|
|
|
if (this._config.type == TetriType.Tetris_BaseGold) { |
|
|
|
//加钱 加银币
|
|
|
|
|
|
|
|
gg.game.CurentBattle.curentCoinNumChange(addNum); |
|
|
|
gg.game.CurentBattle.curentCoinNumChange(addNum); |
|
|
|
|
|
|
|
|
|
|
|
void gg.res.getNodeAsync('角色/', '金币icon', GBundle.tetriCards).then((iconNode) => { |
|
|
|
void gg.res.getNodeAsync('角色/', '金币icon', GBundle.tetriCards).then((iconNode) => { |
|
|
|
if (!iconNode?.isValid) return; |
|
|
|
if (!iconNode?.isValid || !this.node?.isValid) return; |
|
|
|
//播动画
|
|
|
|
this._setupFloatingIcon(iconNode, addNum); |
|
|
|
let jueseNode = this.roleNode//find('角色', this.node)
|
|
|
|
|
|
|
|
iconNode.setParent(jueseNode) |
|
|
|
|
|
|
|
iconNode.active = true |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let lab = iconNode.getChildByName('lab').getComponent(Label) |
|
|
|
|
|
|
|
iconNode.setPosition(0,50) |
|
|
|
|
|
|
|
iconNode.opacity = 100 |
|
|
|
|
|
|
|
lab.string = '+' + addNum.toString() |
|
|
|
|
|
|
|
let posiy = iconNode.y |
|
|
|
|
|
|
|
tween(iconNode) |
|
|
|
|
|
|
|
.to(0.5,{y:150, opacity:255}) |
|
|
|
|
|
|
|
.call(()=>{ |
|
|
|
|
|
|
|
gg.res.putNode(iconNode) |
|
|
|
|
|
|
|
iconNode = null |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.start() |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}else if(this._config.type == TetriType.Tetris_Baseheal){ |
|
|
|
} else if (this._config.type == TetriType.Tetris_Baseheal) { |
|
|
|
//回血
|
|
|
|
|
|
|
|
gg.game.CurentBattle.addWallHp(addNum); |
|
|
|
gg.game.CurentBattle.addWallHp(addNum); |
|
|
|
void gg.res.getNodeAsync('角色/', '爱心icon', GBundle.tetriCards).then((iconNode) => { |
|
|
|
void gg.res.getNodeAsync('角色/', '爱心icon', GBundle.tetriCards).then((iconNode) => { |
|
|
|
if (!iconNode?.isValid) return; |
|
|
|
if (!iconNode?.isValid || !this.node?.isValid) return; |
|
|
|
//播动画
|
|
|
|
this._setupFloatingIcon(iconNode, addNum); |
|
|
|
let jueseNode = this.roleNode//find('角色', this.node)
|
|
|
|
|
|
|
|
iconNode.setParent(jueseNode) |
|
|
|
|
|
|
|
iconNode.active = true |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let lab = iconNode.getChildByName('lab').getComponent(Label) |
|
|
|
|
|
|
|
lab.string = '+' + addNum.toString() |
|
|
|
|
|
|
|
let posiy = iconNode.y |
|
|
|
|
|
|
|
iconNode.setPosition(0,50) |
|
|
|
|
|
|
|
iconNode.opacity = 100 |
|
|
|
|
|
|
|
tween(iconNode) |
|
|
|
|
|
|
|
.to(0.5,{y:150, opacity:255}) |
|
|
|
|
|
|
|
.call(()=>{ |
|
|
|
|
|
|
|
gg.res.putNode(iconNode) |
|
|
|
|
|
|
|
iconNode = null |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.start() |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|