2022-07-28 23:12:21 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
using HeavenStudio;
|
|
|
|
using HeavenStudio.Util;
|
|
|
|
|
|
|
|
namespace HeavenStudio.Games.Scripts_KarateMan
|
|
|
|
{
|
2022-07-29 19:06:22 +00:00
|
|
|
public class KarateManJoe : MonoBehaviour
|
2022-07-28 23:12:21 +00:00
|
|
|
{
|
|
|
|
public Animator anim;
|
2022-08-06 02:37:06 +00:00
|
|
|
public Animator FaceAnim;
|
2022-07-28 23:12:21 +00:00
|
|
|
public GameEvent bop = new GameEvent();
|
2022-08-03 22:55:13 +00:00
|
|
|
public SpriteRenderer[] Shadows;
|
2022-07-28 23:12:21 +00:00
|
|
|
|
2022-08-14 22:59:28 +00:00
|
|
|
public Color BombGlowTint;
|
|
|
|
float bombGlowStart = Single.MinValue;
|
|
|
|
float bombGlowLength = 0f;
|
|
|
|
float bombGlowIntensity;
|
|
|
|
const float bombGlowRatio = 1f;
|
|
|
|
|
2022-07-28 23:12:21 +00:00
|
|
|
float lastPunchTime = Single.MinValue;
|
2022-07-29 02:09:48 +00:00
|
|
|
float lastComboMissTime = Single.MinValue;
|
2022-07-29 16:18:17 +00:00
|
|
|
float lastUpperCutTime = Single.MinValue;
|
2022-07-29 02:09:48 +00:00
|
|
|
public bool inCombo = false;
|
2022-07-29 19:06:22 +00:00
|
|
|
public bool lockedInCombo = false;
|
2022-08-08 00:24:07 +00:00
|
|
|
public bool comboWaiting = false;
|
2022-07-28 23:12:21 +00:00
|
|
|
int inComboId = -1;
|
2022-07-29 02:09:48 +00:00
|
|
|
int shouldComboId = -1;
|
2022-07-28 23:12:21 +00:00
|
|
|
public void SetComboId(int id) { inComboId = id; }
|
2022-07-29 02:09:48 +00:00
|
|
|
public void SetShouldComboId(int id) { shouldComboId = id; }
|
|
|
|
public int GetComboId() { return inComboId; }
|
|
|
|
public int GetShouldComboId() { return shouldComboId; }
|
2022-07-28 23:12:21 +00:00
|
|
|
|
2022-07-30 02:25:48 +00:00
|
|
|
public bool wantKick = false;
|
|
|
|
public bool inKick = false;
|
|
|
|
float lastChargeTime = Single.MinValue;
|
2022-08-07 23:40:06 +00:00
|
|
|
float unPrepareTime = Single.MinValue;
|
2022-08-13 01:06:41 +00:00
|
|
|
float noNuriJabTime = Single.MinValue;
|
2022-08-06 02:37:06 +00:00
|
|
|
bool canEmote = false;
|
2022-08-07 23:40:06 +00:00
|
|
|
public int wantFace = 0;
|
2022-07-30 02:25:48 +00:00
|
|
|
|
2022-08-13 01:06:41 +00:00
|
|
|
public bool inSpecial { get { return inCombo || lockedInCombo ||
|
|
|
|
Conductor.instance.GetPositionFromBeat(lastChargeTime, 2.75f) <= 0.25f || inNuriLock; } }
|
|
|
|
public bool inNuriLock { get { return (Conductor.instance.songPositionInBeats >= noNuriJabTime && Conductor.instance.songPositionInBeats < noNuriJabTime + 1f); } }
|
2022-07-30 02:25:48 +00:00
|
|
|
|
2022-07-28 23:12:21 +00:00
|
|
|
private void Awake()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
private void Update()
|
|
|
|
{
|
|
|
|
var cond = Conductor.instance;
|
2022-08-07 23:40:06 +00:00
|
|
|
|
2022-08-14 22:59:28 +00:00
|
|
|
if (cond.songPositionInBeats < bombGlowStart)
|
|
|
|
{
|
|
|
|
bombGlowIntensity = 1f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float glowProg = cond.GetPositionFromBeat(bombGlowStart, bombGlowLength);
|
|
|
|
bombGlowIntensity = 1f - glowProg;
|
|
|
|
if (cond.songPositionInBeats >= bombGlowStart + bombGlowLength)
|
|
|
|
{
|
|
|
|
bombGlowStart = Single.MinValue;
|
|
|
|
bombGlowLength = 0f;
|
|
|
|
}
|
|
|
|
}
|
2022-08-13 01:06:41 +00:00
|
|
|
UpdateShadowColour();
|
|
|
|
|
|
|
|
if (canEmote && wantFace >= 0)
|
|
|
|
{
|
|
|
|
SetFaceExpressionForced(wantFace);
|
|
|
|
if (wantFace == (int) KarateMan.KarateManFaces.Surprise) wantFace = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cond.songPositionInBeats >= noNuriJabTime && cond.songPositionInBeats < noNuriJabTime + 1f)
|
|
|
|
{
|
|
|
|
anim.DoScaledAnimation("JabNoNuri", noNuriJabTime, 1f);
|
|
|
|
bop.startBeat = noNuriJabTime + 1f;
|
|
|
|
}
|
|
|
|
else if (cond.songPositionInBeats >= noNuriJabTime + 1f && noNuriJabTime != Single.MinValue)
|
|
|
|
{
|
|
|
|
bop.startBeat = noNuriJabTime + 1f;
|
|
|
|
noNuriJabTime = Single.MinValue;
|
|
|
|
}
|
|
|
|
|
2022-08-07 23:40:06 +00:00
|
|
|
if (unPrepareTime != Single.MinValue && cond.songPositionInBeats >= unPrepareTime)
|
|
|
|
{
|
|
|
|
unPrepareTime = Single.MinValue;
|
|
|
|
anim.speed = 1f;
|
|
|
|
anim.Play("Beat", -1, 0);
|
|
|
|
}
|
|
|
|
|
2022-08-12 14:41:41 +00:00
|
|
|
if (cond.ReportBeat(ref bop.lastReportedBeat, bop.startBeat % 1, false) && cond.songPositionInBeats > bop.startBeat && cond.songPositionInBeats < bop.startBeat + bop.length && cond.songPositionInBeats >= unPrepareTime && !inCombo)
|
2022-07-28 23:12:21 +00:00
|
|
|
{
|
2022-08-03 22:55:13 +00:00
|
|
|
anim.speed = 1f;
|
2022-07-28 23:12:21 +00:00
|
|
|
anim.Play("Beat", -1, 0);
|
2022-08-06 02:37:06 +00:00
|
|
|
lastChargeTime = Single.MinValue;
|
2022-07-28 23:12:21 +00:00
|
|
|
}
|
|
|
|
|
2022-07-29 02:09:48 +00:00
|
|
|
if (inCombo && shouldComboId == -2)
|
|
|
|
{
|
2022-07-29 16:18:17 +00:00
|
|
|
float missProg = cond.GetPositionFromBeat(lastComboMissTime, 3f);
|
2022-07-29 02:09:48 +00:00
|
|
|
if (missProg >= 0f && missProg < 1f)
|
|
|
|
{
|
2022-07-29 16:18:17 +00:00
|
|
|
anim.DoScaledAnimation("LowKickMiss", lastComboMissTime, 3f);
|
2022-07-30 02:25:48 +00:00
|
|
|
bop.startBeat = lastComboMissTime + 3f;
|
2022-07-29 02:09:48 +00:00
|
|
|
}
|
|
|
|
else if (missProg >= 1f)
|
|
|
|
{
|
|
|
|
anim.speed = 1f;
|
2022-07-29 16:18:17 +00:00
|
|
|
bop.startBeat = lastComboMissTime + 3f;
|
2022-07-29 02:09:48 +00:00
|
|
|
lastComboMissTime = Single.MinValue;
|
|
|
|
inCombo = false;
|
|
|
|
inComboId = -1;
|
|
|
|
shouldComboId = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-30 02:25:48 +00:00
|
|
|
if (inKick)
|
|
|
|
{
|
2022-07-31 01:16:48 +00:00
|
|
|
float chargeProg = cond.GetPositionFromBeat(lastChargeTime, 2.75f);
|
2022-07-30 02:25:48 +00:00
|
|
|
if (chargeProg >= 0f && chargeProg < 1f)
|
|
|
|
{
|
|
|
|
anim.DoScaledAnimation("ManCharge", lastChargeTime, 2.75f);
|
2022-08-06 02:37:06 +00:00
|
|
|
bop.startBeat = lastChargeTime + 1.75f;
|
2022-07-30 02:25:48 +00:00
|
|
|
}
|
|
|
|
else if (chargeProg >= 1f)
|
|
|
|
{
|
|
|
|
anim.speed = 1f;
|
2022-08-06 02:37:06 +00:00
|
|
|
bop.startBeat = lastChargeTime + 1.75f;
|
2022-07-30 02:25:48 +00:00
|
|
|
lastChargeTime = Single.MinValue;
|
|
|
|
inKick = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PlayerInput.Pressed(true) && !inSpecial)
|
2022-07-28 23:12:21 +00:00
|
|
|
{
|
2022-07-29 19:06:22 +00:00
|
|
|
if (!KarateMan.instance.IsExpectingInputNow())
|
2022-07-28 23:12:21 +00:00
|
|
|
{
|
|
|
|
Punch(1);
|
|
|
|
Jukebox.PlayOneShotGame("karateman/swingNoHit", forcePlay: true);
|
|
|
|
}
|
|
|
|
}
|
2022-08-14 04:34:19 +00:00
|
|
|
|
2022-08-14 21:39:42 +00:00
|
|
|
if (PlayerInput.AltPressed() && KarateMan.IsComboEnable && !inSpecial)
|
2022-07-29 02:09:48 +00:00
|
|
|
{
|
2022-07-29 19:06:22 +00:00
|
|
|
if (!KarateMan.instance.IsExpectingInputNow())
|
2022-07-29 02:09:48 +00:00
|
|
|
{
|
|
|
|
//start a forced-fail combo sequence
|
2022-07-29 16:18:17 +00:00
|
|
|
ForceFailCombo(cond.songPositionInBeats);
|
2022-07-29 02:09:48 +00:00
|
|
|
}
|
|
|
|
}
|
2022-07-28 23:12:21 +00:00
|
|
|
else if (PlayerInput.AltPressedUp())
|
|
|
|
{
|
2022-07-29 19:06:22 +00:00
|
|
|
if (!KarateMan.instance.IsExpectingInputNow())
|
2022-07-28 23:12:21 +00:00
|
|
|
{
|
2022-07-29 19:06:22 +00:00
|
|
|
if (inComboId != -1 && !lockedInCombo)
|
2022-07-28 23:12:21 +00:00
|
|
|
{
|
|
|
|
inComboId = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-30 02:25:48 +00:00
|
|
|
|
2022-07-31 01:16:48 +00:00
|
|
|
if ((!GameManager.instance.autoplay) && (PlayerInput.PressedUp(true) && !PlayerInput.Pressing(true)))
|
2022-07-30 02:25:48 +00:00
|
|
|
{
|
2022-07-31 01:16:48 +00:00
|
|
|
if (wantKick)
|
|
|
|
{
|
|
|
|
//stopped holding, don't charge
|
|
|
|
wantKick = false;
|
|
|
|
}
|
|
|
|
else if (inKick && cond.GetPositionFromBeat(lastChargeTime, 2.75f) <= 0.5f && !KarateMan.instance.IsExpectingInputNow())
|
|
|
|
{
|
|
|
|
Kick(cond.songPositionInBeats);
|
|
|
|
Jukebox.PlayOneShotGame("karateman/swingKick", forcePlay: true);
|
|
|
|
}
|
2022-07-30 02:25:48 +00:00
|
|
|
}
|
2022-08-06 23:15:44 +00:00
|
|
|
|
2022-07-28 23:12:21 +00:00
|
|
|
}
|
|
|
|
|
2022-07-29 02:09:48 +00:00
|
|
|
public bool Punch(int forceHand = 0)
|
2022-07-28 23:12:21 +00:00
|
|
|
{
|
2022-07-29 19:06:22 +00:00
|
|
|
if (GameManager.instance.currentGame != "karateman") return false;
|
2022-07-28 23:12:21 +00:00
|
|
|
var cond = Conductor.instance;
|
2022-07-29 02:09:48 +00:00
|
|
|
bool straight = false;
|
2022-07-31 01:16:48 +00:00
|
|
|
|
|
|
|
anim.speed = 1f;
|
2022-08-07 23:40:06 +00:00
|
|
|
unPrepareTime = Single.MinValue;
|
2022-07-31 01:16:48 +00:00
|
|
|
lastChargeTime = Single.MinValue;
|
|
|
|
inKick = false;
|
|
|
|
|
2022-07-28 23:12:21 +00:00
|
|
|
switch (forceHand)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (cond.songPositionInBeats - lastPunchTime < 0.25f + (Minigame.LateTime() - 1f))
|
|
|
|
{
|
|
|
|
lastPunchTime = Single.MinValue;
|
2022-07-30 02:25:48 +00:00
|
|
|
anim.DoScaledAnimationAsync("Straight", 0.5f);
|
2022-07-29 02:09:48 +00:00
|
|
|
straight = true;
|
2022-07-28 23:12:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lastPunchTime = cond.songPositionInBeats;
|
2022-07-30 02:25:48 +00:00
|
|
|
anim.DoScaledAnimationAsync("Jab", 0.5f);
|
2022-07-28 23:12:21 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
2022-07-30 02:25:48 +00:00
|
|
|
anim.DoScaledAnimationAsync("Jab", 0.5f);
|
2022-07-28 23:12:21 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2022-07-30 02:25:48 +00:00
|
|
|
anim.DoScaledAnimationAsync("Straight", 0.5f);
|
2022-07-29 02:09:48 +00:00
|
|
|
straight = true;
|
2022-07-28 23:12:21 +00:00
|
|
|
break;
|
2022-08-13 01:06:41 +00:00
|
|
|
case 3:
|
|
|
|
lastPunchTime = Single.MinValue;
|
|
|
|
anim.DoNormalizedAnimation("JabNoNuri");
|
|
|
|
noNuriJabTime = cond.songPositionInBeats;
|
|
|
|
break;
|
2022-07-28 23:12:21 +00:00
|
|
|
}
|
|
|
|
bop.startBeat = cond.songPositionInBeats + 0.5f;
|
2022-07-29 02:09:48 +00:00
|
|
|
return straight; //returns what hand was used to punch the object
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ComboSequence(int seq)
|
|
|
|
{
|
2022-07-29 19:06:22 +00:00
|
|
|
if (GameManager.instance.currentGame != "karateman") return;
|
2022-07-29 02:09:48 +00:00
|
|
|
var cond = Conductor.instance;
|
2022-07-29 16:18:17 +00:00
|
|
|
bop.startBeat = cond.songPositionInBeats + 1f;
|
2022-08-07 23:40:06 +00:00
|
|
|
unPrepareTime = Single.MinValue;
|
2022-07-29 02:09:48 +00:00
|
|
|
switch (seq)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
anim.Play("LowJab", -1, 0);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
anim.Play("LowKick", -1, 0);
|
|
|
|
break;
|
|
|
|
case 2:
|
2022-07-29 16:18:17 +00:00
|
|
|
anim.DoScaledAnimationAsync("BackHand", 0.5f);
|
2022-08-08 00:24:07 +00:00
|
|
|
comboWaiting = true;
|
2022-07-29 16:18:17 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
anim.DoScaledAnimationAsync("UpperCut", 0.5f);
|
2022-07-29 19:06:22 +00:00
|
|
|
lockedInCombo = false;
|
2022-08-08 00:24:07 +00:00
|
|
|
comboWaiting = false;
|
2022-07-29 16:18:17 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
anim.Play("ToReady", -1, 0);
|
|
|
|
bop.startBeat = cond.songPositionInBeats + 0.5f;
|
2022-07-29 19:06:22 +00:00
|
|
|
lockedInCombo = false;
|
2022-08-08 00:24:07 +00:00
|
|
|
comboWaiting = false;
|
2022-07-29 02:09:48 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ComboMiss(float beat)
|
|
|
|
{
|
|
|
|
var cond = Conductor.instance;
|
|
|
|
lastComboMissTime = beat;
|
2022-07-29 16:18:17 +00:00
|
|
|
bop.startBeat = beat + 3f;
|
2022-08-07 23:40:06 +00:00
|
|
|
unPrepareTime = Single.MinValue;
|
|
|
|
anim.DoNormalizedAnimation("LowKickMiss");
|
2022-07-29 16:18:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void ForceFailCombo(float beat)
|
|
|
|
{
|
|
|
|
if (inCombo) return;
|
|
|
|
BeatAction.New(gameObject, new List<BeatAction.Action>()
|
|
|
|
{
|
|
|
|
new BeatAction.Action(beat, delegate { Punch(1); inCombo = true; inComboId = -1; shouldComboId = -1;}),
|
|
|
|
new BeatAction.Action(beat + 0.25f, delegate { Punch(2); }),
|
|
|
|
new BeatAction.Action(beat + 0.5f, delegate { ComboSequence(0); }),
|
|
|
|
new BeatAction.Action(beat + 0.75f, delegate { shouldComboId = -2; ComboMiss(beat + 0.75f); }),
|
|
|
|
});
|
|
|
|
|
|
|
|
MultiSound.Play(new MultiSound.Sound[]
|
|
|
|
{
|
|
|
|
new MultiSound.Sound("karateman/swingNoHit", beat),
|
|
|
|
new MultiSound.Sound("karateman/swingNoHit_Alt", beat + 0.25f),
|
|
|
|
new MultiSound.Sound("karateman/swingNoHit_Alt", beat + 0.5f),
|
|
|
|
new MultiSound.Sound("karateman/comboMiss", beat + 0.75f),
|
|
|
|
}, forcePlay: true);
|
2022-07-28 23:12:21 +00:00
|
|
|
}
|
2022-07-30 02:25:48 +00:00
|
|
|
|
|
|
|
public void StartKickCharge(float beat)
|
|
|
|
{
|
|
|
|
wantKick = true;
|
2022-08-07 23:40:06 +00:00
|
|
|
unPrepareTime = Single.MinValue;
|
2022-07-30 02:25:48 +00:00
|
|
|
BeatAction.New(gameObject, new List<BeatAction.Action>()
|
|
|
|
{
|
|
|
|
new BeatAction.Action(beat, delegate {
|
|
|
|
if (wantKick)
|
|
|
|
{
|
|
|
|
wantKick = false;
|
|
|
|
inKick = true;
|
|
|
|
lastChargeTime = beat;
|
2022-08-06 02:37:06 +00:00
|
|
|
bop.startBeat = beat + 1.75f;
|
2022-07-30 02:25:48 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Kick(float beat)
|
|
|
|
{
|
|
|
|
if (!inKick) return;
|
2022-07-31 01:16:48 +00:00
|
|
|
//play the kick animation and reset stance
|
|
|
|
anim.speed = 1f;
|
2022-08-07 23:40:06 +00:00
|
|
|
bop.startBeat = beat + 1f;
|
|
|
|
unPrepareTime = Single.MinValue;
|
2022-07-31 01:16:48 +00:00
|
|
|
lastChargeTime = Single.MinValue;
|
2022-07-30 02:25:48 +00:00
|
|
|
inKick = false;
|
2022-07-31 01:16:48 +00:00
|
|
|
|
|
|
|
anim.DoScaledAnimationAsync("ManKick", 0.5f);
|
2022-07-30 02:25:48 +00:00
|
|
|
}
|
2022-08-03 22:55:13 +00:00
|
|
|
|
2022-08-06 02:37:06 +00:00
|
|
|
public void MarkCanEmote()
|
|
|
|
{
|
|
|
|
canEmote = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void MarkNoEmote()
|
|
|
|
{
|
|
|
|
canEmote = false;
|
|
|
|
}
|
|
|
|
|
2022-08-03 22:55:13 +00:00
|
|
|
public void UpdateShadowColour()
|
|
|
|
{
|
|
|
|
foreach (var shadow in Shadows)
|
|
|
|
{
|
|
|
|
shadow.color = KarateMan.instance.GetShadowColor();
|
|
|
|
}
|
2022-08-14 22:59:28 +00:00
|
|
|
|
|
|
|
Color mainCol = KarateMan.BodyColor;
|
|
|
|
Color highlightCol = KarateMan.HighlightColor;
|
|
|
|
|
|
|
|
if (bombGlowIntensity > 0)
|
|
|
|
{
|
|
|
|
highlightCol = Color.LerpUnclamped(highlightCol, mainCol, bombGlowIntensity);
|
|
|
|
mainCol += BombGlowTint * bombGlowIntensity * bombGlowRatio;
|
|
|
|
}
|
|
|
|
|
|
|
|
KarateMan.instance.MappingMaterial.SetColor("_ColorAlpha", mainCol);
|
|
|
|
KarateMan.instance.MappingMaterial.SetColor("_ColorBravo", new Color(1, 0, 0, 1));
|
|
|
|
KarateMan.instance.MappingMaterial.SetColor("_ColorDelta", highlightCol);
|
2022-08-03 22:55:13 +00:00
|
|
|
}
|
2022-08-06 02:37:06 +00:00
|
|
|
|
2022-08-07 23:40:06 +00:00
|
|
|
public void Prepare(float beat, float length)
|
|
|
|
{
|
|
|
|
anim.speed = 0f;
|
|
|
|
anim.Play("Beat", -1, 0);
|
|
|
|
unPrepareTime = beat + length;
|
|
|
|
}
|
|
|
|
|
2022-08-06 02:37:06 +00:00
|
|
|
public void SetFaceExpressionForced(int face)
|
|
|
|
{
|
|
|
|
FaceAnim.DoScaledAnimationAsync("Face" + face.ToString("D2"));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetFaceExpression(int face, bool ignoreCheck = false)
|
|
|
|
{
|
2022-08-07 23:40:06 +00:00
|
|
|
wantFace = face;
|
2022-08-06 02:37:06 +00:00
|
|
|
if (canEmote || ignoreCheck)
|
|
|
|
FaceAnim.DoScaledAnimationAsync("Face" + face.ToString("D2"));
|
|
|
|
}
|
2022-08-14 22:59:28 +00:00
|
|
|
|
|
|
|
public void ApplyBombGlow()
|
|
|
|
{
|
|
|
|
bombGlowStart = Single.MaxValue;
|
|
|
|
bombGlowLength = 0f;
|
|
|
|
bombGlowIntensity = 1f;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void RemoveBombGlow(float beat, float length = 0.5f)
|
|
|
|
{
|
|
|
|
bombGlowStart = beat;
|
|
|
|
bombGlowLength = length;
|
|
|
|
bombGlowIntensity = 0f;
|
|
|
|
}
|
2022-07-28 23:12:21 +00:00
|
|
|
}
|
|
|
|
}
|