You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1886 lines
67 KiB

-- WarlockAffliction.lua
-- June 2018
local addon, ns = ...
local Hekili = _G[ addon ]
local class = Hekili.Class
local state = Hekili.State
-- Conduits
-- [-] cold_embrace
-- [-] corrupting_leer
-- [-] focused_malignancy
-- [x] rolling_agony
-- Covenants
-- [x] soul_tithe
-- [x] catastrophic_origin
-- [-] prolonged_decimation
-- [-] soul_eater
-- Endurance
-- [x] accrued_vitality
-- [-] diabolic_bloodstone
-- [-] resolute_barrier
-- Finesse
-- [x] demonic_momentum
-- [x] fel_celerity
-- [-] shade_of_terror
if UnitClassBase( "player" ) == 'WARLOCK' then
local spec = Hekili:NewSpecialization( 265, true )
spec:RegisterResource( Enum.PowerType.SoulShards, {
-- regen effects.
}, setmetatable( {
actual = nil,
max = 5,
active_regen = 0,
inactive_regen = 0,
forecast = {},
times = {},
values = {},
fcount = 0,
regen = 0,
regenerates = false,
}, {
__index = function( t, k )
if k == "count" or k == "current" then return t.actual
elseif k == "actual" then
t.actual = UnitPower( "player", Enum.PowerType.SoulShards )
return t.actual
else
local amount = k:match( "time_to_(%d+)" )
amount = amount and tonumber( amount )
if amount then return state:TimeToResource( t, amount ) end
end
end
} ) )
spec:RegisterResource( Enum.PowerType.Mana )
-- Talents
spec:RegisterTalents( {
nightfall = 22039, -- 108558
inevitable_demise = 23140, -- 334319
drain_soul = 23141, -- 198590
writhe_in_agony = 22044, -- 196102
absolute_corruption = 21180, -- 196103
siphon_life = 22089, -- 63106
demon_skin = 19280, -- 219272
burning_rush = 19285, -- 111400
dark_pact = 19286, -- 108416
sow_the_seeds = 19279, -- 196226
phantom_singularity = 19292, -- 205179
vile_taint = 22046, -- 278350
darkfury = 22047, -- 264874
mortal_coil = 19291, -- 6789
howl_of_terror = 23465, -- 5484
shadow_embrace = 23139, -- 32388
haunt = 23159, -- 48181
grimoire_of_sacrifice = 19295, -- 108503
soul_conduit = 19284, -- 215941
creeping_death = 19281, -- 264000
dark_soul_misery = 19293, -- 113860
} )
-- PvP Talents
spec:RegisterPvpTalents( {
amplify_curse = 5370, -- 328774
bane_of_fragility = 11, -- 199954
bane_of_shadows = 17, -- 234877
casting_circle = 20, -- 221703
deathbolt = 12, -- 264106
demon_armor = 3740, -- 285933
essence_drain = 19, -- 221711
gateway_mastery = 15, -- 248855
nether_ward = 18, -- 212295
rampant_afflictions = 5379, -- 335052
rapid_contagion = 5386, -- 344566
rot_and_decay = 16, -- 212371
shadow_rift = 5392, -- 353294
} )
-- Auras
spec:RegisterAuras( {
agony = {
id = 980,
duration = function () return ( 18 + conduit.rolling_agony.mod * 0.001 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) * haste end,
type = "Curse",
max_stack = function () return ( talent.writhe_in_agony.enabled and 18 or 10 ) end,
meta = {
stack = function( t )
if t.down then return 0 end
if t.count >= 10 then return t.count end
local app = t.applied
local tick = t.tick_time
local last_real_tick = now + ( floor( ( now - app ) / tick ) * tick )
local ticks_since = floor( ( query_time - last_real_tick ) / tick )
return min( talent.writhe_in_agony.enabled and 18 or 10, t.count + ticks_since )
end,
}
},
burning_rush = {
id = 111400,
duration = 3600,
max_stack = 1,
},
corruption = {
id = 146739,
duration = function () return ( talent.absolute_corruption.enabled and ( target.is_player and 24 or 3600 ) or 14 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) * haste end,
type = "Magic",
max_stack = 1,
},
curse_of_exhaustion = {
id = 334275,
duration = 8,
max_stack = 1,
},
curse_of_tongues = {
id = 1714,
duration = 60,
type = "Curse",
max_stack = 1,
},
curse_of_weakness = {
id = 702,
duration = 120,
type = "Curse",
max_stack = 1,
},
dark_pact = {
id = 108416,
duration = 20,
max_stack = 1,
},
dark_soul_misery = {
id = 113860,
duration = 20,
max_stack = 1,
},
decimating_bolt = {
id = 325299,
duration = 3600,
max_stack = 1,
},
demonic_circle = {
id = 48018,
duration = 900,
max_stack = 1,
},
demonic_circle_teleport = {
id = 48020,
},
drain_life = {
id = 234153,
duration = function () return 5 * haste * ( legendary.claw_of_endereth.enabled and 0.5 or 1 ) end,
max_stack = 1,
tick_time = function () return haste * ( legendary.claw_of_endereth.enabled and 0.5 or 1 ) end,
},
drain_soul = {
id = 198590,
duration = function () return 5 * haste end,
max_stack = 1,
tick_time = function ()
if not settings.manage_ds_ticks then return nil end
return haste
end,
},
eye_of_kilrogg = {
id = 126,
duration = 45,
max_stack = 1,
},
fear = {
id = 118699,
duration = 20,
type = "Magic",
max_stack = 1,
},
fel_domination = {
id = 333889,
duration = 15,
type = "Magic",
max_stack = 1,
},
grimoire_of_sacrifice = {
id = 196099,
duration = 3600,
max_stack = 1,
},
haunt = {
id = 48181,
duration = 18,
type = "Magic",
max_stack = 1,
},
howl_of_terror = {
id = 5484,
duration = 20,
max_stack = 1,
},
inevitable_demise = {
id = 334320,
duration = 20,
type = "Magic",
max_stack = 50,
copy = 273525
},
mortal_coil = {
id = 6789,
duration = 3,
type = "Magic",
max_stack = 1,
},
nightfall = {
id = 264571,
duration = 12,
max_stack = 1,
},
phantom_singularity = {
id = 205179,
duration = 16,
max_stack = 1,
},
ritual_of_summoning = {
id = 698,
},
seed_of_corruption = {
id = 27243,
duration = 12,
type = "Magic",
max_stack = 1,
},
shadow_embrace = {
id = 32390,
duration = 16,
type = "Magic",
max_stack = 3,
},
shadowfury = {
id = 30283,
duration = 3,
type = "Magic",
max_stack = 1,
},
siphon_life = {
id = 63106,
duration = function () return 15 * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
tick_time = function () return 3 * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
type = "Magic",
max_stack = 1,
},
soul_leech = {
id = 108366,
duration = 15,
max_stack = 1,
},
soul_shards = {
id = 246985,
},
soulstone = {
id = 20707,
duration = 900,
max_stack = 1,
},
summon_darkglare = {
id = 205180,
},
unending_breath = {
id = 5697,
duration = 600,
max_stack = 1,
},
unending_resolve = {
id = 104773,
duration = 8,
max_stack = 1,
},
unstable_affliction = {
id = function () return pvptalent.rampant_afflictions.enabled and 342938 or 316099 end,
duration = function () return level > 55 and 21 or 16 end,
tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) * haste end,
type = "Magic",
max_stack = 1,
copy = { 342938, 316099 }
},
--[[ OLD UAs:
unstable_affliction = {
id = 233490,
duration = function () return ( pvptalent.endless_affliction.enabled and 14 or 8 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
type = "Magic",
max_stack = 1,
copy = "unstable_affliction_1"
},
unstable_affliction_2 = {
id = 233496,
duration = function () return ( pvptalent.endless_affliction.enabled and 14 or 8 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
type = "Magic",
max_stack = 1,
},
unstable_affliction_3 = {
id = 233497,
duration = function () return ( pvptalent.endless_affliction.enabled and 14 or 8 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
type = "Magic",
max_stack = 1,
},
unstable_affliction_4 = {
id = 233498,
duration = function () return ( pvptalent.endless_affliction.enabled and 14 or 8 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
type = "Magic",
max_stack = 1,
},
unstable_affliction_5 = {
id = 233499,
duration = function () return ( pvptalent.endless_affliction.enabled and 14 or 8 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) end,
type = "Magic",
max_stack = 1,
},
active_uas = {
alias = { "unstable_affliction_1", "unstable_affliction_2", "unstable_affliction_3", "unstable_affliction_4", "unstable_affliction_5" },
aliasMode = "longest",
aliasType = "debuff",
duration = 8
}, ]]
vile_taint = {
id = 278350,
duration = 10,
type = "Magic",
max_stack = 1,
},
-- PvP Talents
casting_circle = {
id = 221705,
duration = 3600,
max_stack = 1,
},
curse_of_fragility = {
id = 199954,
duration = 10,
max_stack = 1,
},
curse_of_shadows = {
id = 234877,
duration = 10,
type = "Curse",
max_stack = 1,
},
demon_armor = {
id = 285933,
duration = 3600,
max_stack = 1,
},
essence_drain = {
id = 221715,
duration = 10,
type = "Magic",
max_stack = 5,
},
nether_ward = {
id = 212295,
duration = 3,
type = "Magic",
max_stack = 1,
},
soulshatter = {
id = 236471,
duration = 8,
max_stack = 5,
},
-- Conduit
diabolic_bloodstone = {
id = 340563,
duration = 8,
max_stack = 1
},
-- Legendaries
malefic_wrath = {
id = 337125,
duration = 8,
max_stack = 1
},
relic_of_demonic_synergy = {
id = 337060,
duration = 15,
max_stack = 1
},
wrath_of_consumption = {
id = 337130,
duration = 20,
max_stack = 5
}
} )
spec:RegisterHook( "TimeToReady", function( wait, action )
local ability = action and class.abilities[ action ]
if ability and ability.spend and ability.spendType == "soul_shards" and ability.spend > soul_shard then
wait = 3600
end
return wait
end )
spec:RegisterStateExpr( "soul_shard", function () return soul_shards.current end )
state.sqrt = math.sqrt
spec:RegisterStateExpr( "time_to_shard", function ()
local num_agony = active_dot.agony
if num_agony == 0 then return 3600 end
return 1 / ( 0.16 / sqrt( num_agony ) * ( num_agony == 1 and 1.15 or 1 ) * num_agony / debuff.agony.tick_time )
end )
spec:RegisterHook( "COMBAT_LOG_EVENT_UNFILTERED", function( _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName, _, amount, interrupt, a, b, c, d, offhand, multistrike, ... )
if sourceGUID == GUID and spellName == class.abilities.seed_of_corruption.name then
if subtype == "SPELL_CAST_SUCCESS" then
action.seed_of_corruption.flying = GetTime()
elseif subtype == "SPELL_AURA_APPLIED" or subtype == "SPELL_AURA_REFRESH" then
action.seed_of_corruption.flying = 0
end
end
end, false )
spec:RegisterGear( "tier28", 188884, 188887, 188888, 188889, 188890 )
-- Tier 28
spec:RegisterSetBonuses( "tier28_2pc", 364437, "tier28_4pc", 363953 )
-- 2-Set - Deliberate Malice - Malefic Rapture's damage is increased by 15% and each cast extends the duration of Corruption, Agony, and Unstable Affliction by 2 sec.
-- 4-Set - Calamitous Crescendo - While Agony, Corruption, and Unstable Affliction are active, your Drain Soul has a 10% chance / Shadow Bolt has a 20% chance to make your next Malefic Rapture cost no Soul Shards and cast instantly.
spec:RegisterAura( "calamitous_crescendo", {
id = 364322,
duration = 10,
max_stack = 1,
} )
spec:RegisterGear( "tier21", 152174, 152177, 152172, 152176, 152173, 152175 )
spec:RegisterGear( "tier20", 147183, 147186, 147181, 147185, 147182, 147184 )
spec:RegisterGear( "tier19", 138314, 138323, 138373, 138320, 138311, 138317 )
spec:RegisterGear( "class", 139765, 139768, 139767, 139770, 139764, 139769, 139766, 139763 )
spec:RegisterGear( "amanthuls_vision", 154172 )
spec:RegisterGear( "hood_of_eternal_disdain", 132394 )
spec:RegisterGear( "norgannons_foresight", 132455 )
spec:RegisterGear( "pillars_of_the_dark_portal", 132357 )
spec:RegisterGear( "power_cord_of_lethtendris", 132457 )
spec:RegisterGear( "reap_and_sow", 144364 )
spec:RegisterGear( "sacrolashs_dark_strike", 132378 )
spec:RegisterGear( "soul_of_the_netherlord", 151649 )
spec:RegisterGear( "stretens_sleepless_shackles", 132381 )
spec:RegisterGear( "the_master_harvester", 151821 )
--[[ spec:RegisterStateFunction( "applyUnstableAffliction", function( duration )
for i = 1, 5 do
local aura = "unstable_affliction_" .. i
if debuff[ aura ].down then
applyDebuff( "target", aura, duration or 8 )
break
end
end
end ) ]]
spec:RegisterHook( "reset_preauras", function ()
if class.abilities.summon_darkglare.realCast and state.now - class.abilities.summon_darkglare.realCast < 20 then
target.updated = true
end
end )
local SUMMON_DEMON_TEXT
spec:RegisterHook( "reset_precast", function ()
soul_shards.actual = nil
local icd = 25
if debuff.drain_soul.up then
local ticks = debuff.drain_soul.ticks_remain
if pvptalent.rot_and_decay.enabled then
if debuff.agony.up then debuff.agony.expires = debuff.agony.expires + 1 end
if debuff.corruption.up then debuff.corruption.expires = debuff.corruption.expires + 1 end
if debuff.unstable_affliction.up then debuff.unstable_affliction.expires = debuff.unstable_affliction.expires + 1 end
end
if pvptalent.essence_drain.enabled and health.pct < 100 then
addStack( "essence_drain", debuff.drain_soul.remains, debuff.essence_drain.stack + ticks )
end
end
-- Can't trust Agony stacks/duration to refresh.
local name, _, count, _, duration, expires, caster = FindUnitDebuffByID( "target", 980 )
if name then
debuff.agony.expires = expires
debuff.agony.duration = duration
debuff.agony.applied = max( 0, expires - duration )
debuff.agony.count = expires > 0 and max( 1, count ) or 0
debuff.agony.caster = caster
else
debuff.agony.expires = 0
debuff.agony.duration = 0
debuff.agony.applied = 0
debuff.agony.count = 0
debuff.agony.caster = "nobody"
end
if buff.casting.up and buff.casting.v1 == 234153 then
removeBuff( "inevitable_demise" )
removeBuff( "inevitable_demise_az" )
end
if buff.casting_circle.up then
applyBuff( "casting_circle", action.casting_circle.lastCast + 8 - query_time )
end
class.abilities.summon_pet = class.abilities.summon_felhunter
if not SUMMON_DEMON_TEXT then
SUMMON_DEMON_TEXT = GetSpellInfo( 180284 )
class.abilityList.summon_pet = "|T136082:0|t |cff00ccff[" .. ( SUMMON_DEMON_TEXT or "Summon Demon" ) .. "]|r"
end
end )
spec:RegisterHook( "spend", function( amt, resource )
if resource == "soul_shards" and amt > 0 then
if legendary.wilfreds_sigil_of_superior_summoning.enabled then
reduceCooldown( "summon_darkglare", amt * 2 )
end
end
end )
spec:RegisterStateExpr( "target_uas", function ()
return active_dot.unstable_affliction
end )
spec:RegisterStateExpr( "contagion", function ()
return active_dot.unstable_affliction > 0
end )
spec:RegisterStateExpr( "can_seed", function ()
local seed_targets = min( active_enemies, Hekili:GetNumTTDsAfter( action.seed_of_corruption.cast + ( 6 * haste ) ) )
if active_dot.seed_of_corruption < seed_targets - ( state:IsInFlight( "seed_of_corruption" ) and 1 or 0 ) then return true end
return false
end )
local Glyphed = IsSpellKnownOrOverridesKnown
-- Fel Imp 58959
spec:RegisterPet( "imp",
function() return Glyphed( 112866 ) and 58959 or 416 end,
"summon_imp",
3600 )
-- Voidlord 58960
spec:RegisterPet( "voidwalker",
function() return Glyphed( 112867 ) and 58960 or 1860 end,
"summon_voidwalker",
3600 )
-- Observer 58964
spec:RegisterPet( "felhunter",
function() return Glyphed( 112869 ) and 58964 or 417 end,
"summon_felhunter",
3600 )
-- Fel Succubus 120526
-- Shadow Succubus 120527
-- Shivarra 58963
spec:RegisterPet( "sayaad",
function()
if Glyphed( 240263 ) then return 120526
elseif Glyphed( 240266 ) then return 120527
elseif Glyphed( 112868 ) then return 58963
elseif Glyphed( 365349 ) then return 184600
end
return 1863
end,
"summon_sayaad",
3600,
"incubus", "succubus" )
-- Wrathguard 58965
spec:RegisterPet( "felguard",
function() return Glyphed( 112870 ) and 58965 or 17252 end,
"summon_felguard",
3600 )
-- Abilities
spec:RegisterAbilities( {
agony = {
id = 980,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 136139,
handler = function ()
applyDebuff( "target", "agony", nil, max( ( talent.writhe_in_agony.enabled or azerite.sudden_onset.enabled ) and 4 or 1, debuff.agony.stack ) )
end,
},
--[[ banish = {
id = 710,
cast = 1.5,
cooldown = 0,
gcd = "spell",
spend = 0.02,
spendType = "mana",
startsCombat = true,
handler = function ()
end,
}, ]]
burning_rush = {
id = 111400,
cast = 0,
cooldown = 0,
gcd = function () return buff.burning_rush.up and "off" or "spell" end,
startsCombat = true,
talent = "burning_rush",
texture = 538043,
handler = function ()
if buff.burning_rush.down then applyBuff( "burning_rush" )
else removeBuff( "burning_rush" ) end
end,
},
casting_circle = {
id = 221703,
cast = 0.5,
cooldown = 60,
gcd = "spell",
spend = 0.02,
spendType = "mana",
pvptalent = "casting_circle",
startsCombat = false,
texture = 1392953,
handler = function ()
applyBuff( "casting_circle", 8 )
end,
},
--[[ command_demon = {
id = 119898,
cast = 0,
cooldown = 0,
gcd = "spell",
startsCombat = true,
handler = function ()
end,
}, ]]
corruption = {
id = 172,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 136118,
handler = function ()
applyDebuff( "target", "corruption" )
end,
},
--[[ create_healthstone = {
id = 6201,
cast = 3,
cooldown = 0,
gcd = "spell",
spend = 0.02,
spendType = "mana",
startsCombat = true,
handler = function ()
end,
},
create_soulwell = {
id = 29893,
cast = 3,
cooldown = 120,
gcd = "spell",
spend = 0.05,
spendType = "mana",
toggle = "cooldowns",
startsCombat = true,
handler = function ()
end,
}, ]]
curse_of_exhaustion = {
id = 334275,
cast = 0,
cooldown = 0,
gcd = "spell",
startsCombat = true,
texture = 136162,
handler = function ()
applyDebuff( "target", "curse_of_exhaustion" )
removeDebuff( "target", "curse_of_tongues" )
removeDebuff( "target", "curse_of_weakness" )
end,
},
curse_of_fragility = {
id = 199954,
cast = 0,
cooldown = 45,
gcd = "spell",
spend = 0.01,
spendType = "mana",
pvptalent = "curse_of_fragility",
startsCombat = true,
texture = 132097,
usable = function () return target.is_player end,
handler = function ()
applyDebuff( "target", "curse_of_fragility" )
setCooldown( "curse_of_tongues", max( 6, cooldown.curse_of_tongues.remains ) )
setCooldown( "curse_of_weakness", max( 6, cooldown.curse_of_weakness.remains ) )
end,
},
curse_of_tongues = {
id = 1714,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.01,
spendType = "mana",
pvptalent = "curse_of_tongues",
startsCombat = true,
texture = 136140,
handler = function ()
applyDebuff( "target", "curse_of_tongues" )
removeDebuff( "target", "curse_of_exhaustion" )
removeDebuff( "target", "curse_oF_weakness" )
setCooldown( "curse_of_fragility", max( 6, cooldown.curse_of_fragility.remains ) )
setCooldown( "curse_of_weakness", max( 6, cooldown.curse_of_weakness.remains ) )
end,
},
curse_of_weakness = {
id = 702,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 615101,
handler = function ()
applyDebuff( "target", "curse_of_weakness" )
removeDebuff( "target", "curse_of_exhaustion" )
removeDebuff( "target", "curse_oF_tongues" )
setCooldown( "curse_of_fragility", max( 6, cooldown.curse_of_fragility.remains ) )
setCooldown( "curse_of_tongues", max( 6, cooldown.curse_of_tongues.remains ) )
end,
},
dark_pact = {
id = 108416,
cast = 0,
cooldown = 60,
gcd = "spell",
toggle = "defensives",
startsCombat = false,
texture = 538538,
talent = "dark_pact",
handler = function ()
spend( 0.2 * health.current, "health" )
applyBuff( "dark_pact" )
end,
},
dark_soul = {
id = 113860,
cast = 0,
cooldown = 120,
gcd = "off",
toggle = "cooldowns",
spend = 0.01,
spendType = "mana",
startsCombat = false,
texture = 463286,
talent = "dark_soul_misery",
handler = function ()
applyBuff( "dark_soul_misery" )
stat.haste = stat.haste + 0.3
end,
copy = "dark_soul_misery"
},
deathbolt = {
id = 264106,
cast = 1,
cooldown = 30,
gcd = "spell",
spend = 0.02,
spendType = "mana",
startsCombat = true,
pvptalent = "deathbolt",
handler = function ()
end,
},
demon_armor = {
id = 285933,
cast = 0,
cooldown = 0,
gcd = "spell",
pvptalent = "demon_armor",
startsCombat = false,
texture = 136185,
handler = function ()
applyBuff( "demon_armor" )
end,
},
--[[ demonic_circle = {
id = 48018,
cast = 0.5,
cooldown = 10,
gcd = "spell",
spend = 0.02,
spendType = "mana",
startsCombat = true,
handler = function ()
end,
},
demonic_circle_teleport = {
id = 48020,
cast = 0,
cooldown = 30,
gcd = "spell",
spend = 0.03,
spendType = "mana",
startsCombat = true,
handler = function ()
end,
-- Conduit in WarlockDemonology.lua
},
demonic_gateway = {
id = 111771,
cast = 2,
cooldown = 10,
gcd = "spell",
spend = 0.2,
spendType = "mana",
startsCombat = true,
handler = function ()
end,
}, ]]
devour_magic = {
id = 19505,
cast = 0,
cooldown = 15,
gcd = "off",
spend = 0,
spendType = "mana",
startsCombat = true,
toggle = "interrupts",
usable = function ()
if buff.dispellable_magic.down then return false, "no dispellable magic aura" end
return true
end,
handler = function()
removeBuff( "dispellable_magic" )
end,
},
drain_life = {
id = 234153,
cast = function () return 5 * haste * ( legendary.claw_of_endereth.enabled and 0.5 or 1 ) end,
channeled = true,
breakable = true,
cooldown = 0,
gcd = "spell",
spend = function () return active_dot.soul_rot == 1 and 0 or 0.03 end,
spendType = "mana",
startsCombat = true,
texture = 136169,
tick_time = function () return class.auras.drain_life.tick_time end,
start = function ()
removeBuff( "inevitable_demise" )
removeBuff( "inevitable_demise_az" )
end,
finish = function ()
if conduit.accrued_vitality.enabled then applyBuff( "accrued_vitality" ) end
end,
auras = {
-- Conduit
accrued_vitality = {
id = 339298,
duration = 10,
max_stack = 1
},
-- Azerite
inevitable_demise_az = {
id = 273525,
duration = 20,
max_stack = 50
}
}
},
drain_soul = {
id = 198590,
cast = 5,
channeled = true,
cooldown = 0,
gcd = "spell",
prechannel = true,
breakable = true,
breakchannel = function () removeDebuff( "target", "drain_soul" ) end,
spend = 0.01,
spendType = "mana",
startsCombat = true,
talent = "drain_soul",
texture = 136163,
break_any = function ()
if not settings.manage_ds_ticks then return true end
return nil
end,
tick_time = function ()
if not talent.shadow_embrace.enabled or not settings.manage_ds_ticks then return nil end
return class.auras.drain_soul.tick_time
end,
start = function ()
applyDebuff( "target", "drain_soul" )
applyBuff( "casting", 5 * haste )
channelSpell( "drain_soul" )
removeStack( "decimating_bolt" )
removeBuff( "malefic_wrath" )
if talent.shadow_embrace.enabled then applyDebuff( "target", "shadow_embrace", nil, debuff.shadow_embrace.stack + 1 ) end
end,
tick = function ()
if not settings.manage_ds_ticks or not talent.shadow_embrace.enabled then return end
applyDebuff( "target", "shadow_embrace", nil, debuff.shadow_embrace.stack + 1 )
end,
},
--[[ enslave_demon = {
id = 1098,
cast = 3,
cooldown = 0,
gcd = "spell",
spend = 0.02,
spendType = "mana",
startsCombat = true,
handler = function ()
end,
},
eye_of_kilrogg = {
id = 126,
cast = 2,
cooldown = 0,
gcd = "spell",
spend = 0.03,
spendType = "mana",
startsCombat = true,
handler = function ()
end,
}, ]]
fear = {
id = 5782,
cast = 1.7,
cooldown = 0,
gcd = "spell",
spend = 0.05,
spendType = "mana",
startsCombat = true,
handler = function ()
applyDebuff( "target", "fear" )
end,
},
fel_domination = {
id = 333889,
cast = 0,
cooldown = function () return 180 + conduit.fel_celerity.mod * 0.001 end,
gcd = "spell",
startsCombat = false,
texture = 237564,
essential = true,
nomounted = true,
nobuff = "grimoire_of_sacrifice",
handler = function ()
applyBuff( "fel_domination" )
end,
},
grimoire_of_sacrifice = {
id = 108503,
cast = 0,
cooldown = 30,
gcd = "spell",
startsCombat = false,
texture = 538443,
usable = function () return pet.exists and buff.grimoire_of_sacrifice.down end,
handler = function ()
applyBuff( "grimoire_of_sacrifice" )
end,
},
haunt = {
id = 48181,
cast = 1.5,
cooldown = 15,
gcd = "spell",
spend = 0.02,
spendType = "mana",
startsCombat = true,
texture = 236298,
talent = "haunt",
handler = function ()
applyDebuff( "target", "haunt" )
if level > 51 then applyDebuff( "target", "shadow_embrace", nil, debuff.shadow_embrace.stack + 1 ) end
end,
},
health_funnel = {
id = 755,
cast = 5,
channeled = true,
breakable = true,
cooldown = 0,
gcd = "spell",
startsCombat = false,
texture = 136168,
start = function ()
end,
},
howl_of_terror = {
id = 5484,
cast = 0,
cooldown = 40,
gcd = "spell",
startsCombat = true,
texture = 607852,
talent = "howl_of_terror",
handler = function ()
applyDebuff( "target", "howl_of_terror" )
end,
},
malefic_rapture = {
id = 324536,
cast = function () return buff.calamitous_crescendo.up and 0 or 1.5 end,
cooldown = 0,
gcd = "spell",
spend = function () return buff.calamitous_crescendo.up and 0 or 1 end,
spendType = "soul_shards",
startsCombat = true,
texture = 236296,
handler = function ()
if legendary.malefic_wrath.enabled then addStack( "malefic_wrath", nil, 1 ) end
if set_bonus.tier28_2pc > 0 then
if debuff.corruption.up then debuff.corruption.expires = debuff.corruption.expires + 2 end
if debuff.agony.up then debuff.agony.expires = debuff.agony.expires + 2 end
if debuff.unstable_affliction.up then debuff.unstable_affliction.expires = debuff.unstable_affliction.expires + 2 end
end
if buff.calamitous_crescendo.up then removeBuff( "calamitous_crescendo" ) end
end,
},
mortal_coil = {
id = 6789,
cast = 0,
cooldown = 45,
gcd = "spell",
spend = 0.02,
spendType = "mana",
startsCombat = true,
texture = 607853,
talent = "mortal_coil",
handler = function ()
applyDebuff( "target", "mortal_coil" )
gain( 0.2 * health.max, "health" )
end,
},
nether_ward = {
id = 212295,
cast = 0,
cooldown = 45,
gcd = "spell",
pvptalent = "nether_ward",
startsCombat = false,
texture = 135796,
handler = function ()
applyBuff( "nether_ward" )
end,
},
phantom_singularity = {
id = 205179,
cast = 0,
cooldown = 45,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 132886,
talent = "phantom_singularity",
handler = function ()
applyDebuff( "target", "phantom_singularity" )
end,
},
--[[ ritual_of_summoning = {
id = 698,
cast = 0,
cooldown = 120,
gcd = "spell",
spend = 0,
spendType = "mana",
toggle = "cooldowns",
startsCombat = true,
handler = function ()
end,
}, ]]
seed_of_corruption = {
id = 27243,
cast = 2.5,
cooldown = 0,
gcd = "spell",
spend = 1,
spendType = "soul_shards",
startsCombat = true,
texture = 136193,
velocity = 30,
usable = function () return dot.seed_of_corruption.down end,
impact = function ()
applyDebuff( "target", "seed_of_corruption" )
if active_enemies > 1 and talent.sow_the_seeds.enabled then
active_dot.seed_of_corruption = min( active_enemies, active_dot.seed_of_corruption + 2 )
end
end,
},
shadow_bolt = {
id = 686,
cast = 2,
cooldown = 0,
gcd = "spell",
spend = 0.02,
spendType = "mana",
startsCombat = true,
texture = 136197,
velocity = 20,
notalent = "drain_soul",
cycle = function () return talent.shadow_embrace.enabled and "shadow_embrace" or nil end,
handler = function ()
removeBuff( "malefic_wrath" )
end,
impact = function ()
if talent.shadow_embrace.enabled then applyDebuff( "target", "shadow_embrace", nil, debuff.shadow_embrace.stack + 1 ) end
end,
},
shadowfury = {
id = 30283,
cast = 1.5,
cooldown = 60,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 607865,
handler = function ()
applyDebuff( "target", "shadowfury" )
end,
},
siphon_life = {
id = 63106,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 136188,
talent = "siphon_life",
handler = function ()
applyDebuff( "target", "siphon_life" )
end,
},
soulstone = {
id = 20707,
cast = 3,
cooldown = 600,
gcd = "spell",
startsCombat = false,
handler = function ()
applyBuff( "soulstone" )
end,
},
spell_lock = {
id = 19647,
known = function () return IsSpellKnownOrOverridesKnown( 119910 ) or IsSpellKnownOrOverridesKnown( 132409 ) end,
cast = 0,
cooldown = 24,
gcd = "off",
spend = 0.02,
spendType = "mana",
startsCombat = true,
texture = 136174,
toggle = "interrupts",
debuff = "casting",
readyTime = state.timeToInterrupt,
handler = function ()
interrupt()
end,
},
summon_darkglare = {
id = 205180,
cast = 0,
cooldown = function () return ( essence.vision_of_perfection.enabled and 0.87 or 1 ) * ( level > 57 and 120 or 180 ) end,
gcd = "spell",
spend = 0.02,
spendType = "mana",
toggle = "cooldowns",
startsCombat = true,
texture = 1416161,
handler = function ()
summonPet( "darkglare", 20 )
if debuff.agony.up then debuff.agony.expires = debuff.agony.expires + 8 end
if debuff.corruption.up then debuff.corruption.expires = debuff.corruption.expires + 8 end
-- if debuff.impending_catastrophe.up then debuff.impending_catastrophe.expires = debuff.impending_catastrophe.expires + 8 end
if debuff.scouring_tithe.up then debuff.scouring_tithe.expires = debuff.scouring_tithe.expires + 8 end
if debuff.siphon_life.up then debuff.siphon_life.expires = debuff.siphon_life.expires + 8 end
if debuff.soul_rot.up then debuff.soul_rot.expires = debuff.soul_rot.expires + 8 end
if debuff.unstable_affliction.up then debuff.unstable_affliction.expires = debuff.unstable_affliction.expires + 8 end
end,
},
summon_imp = {
id = 688,
cast = function () return ( buff.fel_domination.up and 0.5 or 6 ) * haste end,
cooldown = 0,
gcd = "spell",
spend = function () return buff.fel_domination.up and 0 or 1 end,
spendType = "soul_shards",
usable = function () return not pet.alive end,
handler = function () summonPet( "imp" ) end,
},
summon_voidwalker = {
id = 697,
cast = function () return ( buff.fel_domination.up and 0.5 or 6 ) * haste end,
cooldown = 0,
gcd = "spell",
spend = function () return buff.fel_domination.up and 0 or 1 end,
spendType = "soul_shards",
usable = function () return not pet.alive end,
handler = function () summonPet( "voidwalker" ) end,
},
summon_felhunter = {
id = 691,
cast = function () return ( buff.fel_domination.up and 0.5 or 6 ) * haste end,
cooldown = 0,
gcd = "spell",
spend = function () return buff.fel_domination.up and 0 or 1 end,
spendType = "soul_shards",
essential = true,
nomounted = true,
bind = "summon_pet",
usable = function ()
if pet.alive then return false, "pet is alive"
elseif buff.grimoire_of_sacrifice.up then return false, "grimoire_of_sacrifice is up" end
return true
end,
handler = function ()
removeBuff( "fel_domination" )
summonPet( "felhunter" )
end,
copy = { "summon_pet", 112869 }
},
summon_sayaad = {
id = 366222,
cast = function () return ( buff.fel_domination.up and 0.5 or 6 ) * haste end,
cooldown = 0,
gcd = "spell",
spend = function () return buff.fel_domination.up and 0 or 1 end,
spendType = "soul_shards",
usable = function () return not pet.alive end,
handler = function () summonPet( "sayaad" ) end,
copy = { "summon_incubus", "summon_succubus" }
},
unending_breath = {
id = 5697,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.02,
spendType = "mana",
startsCombat = false,
texture = 136148,
handler = function ()
applyBuff( "unending_breath" )
end,
},
unending_resolve = {
id = 104773,
cast = 0,
cooldown = 180,
gcd = "spell",
spend = 0.02,
spendType = "mana",
toggle = "defensives",
startsCombat = true,
handler = function ()
applyBuff( "unending_resolve" )
end,
},
unstable_affliction = {
id = function () return pvptalent.rampant_afflictions.enabled and 342938 or 316099 end,
cast = 1.5,
cooldown = 0,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 136228,
handler = function ()
if azerite.cascading_calamity.enabled and debuff.unstable_affliction.up then
applyBuff( "cascading_calamity" )
end
applyDebuff( "target", "unstable_affliction" )
if azerite.dreadful_calling.enabled then
gainChargeTime( "summon_darkglare", 1 )
end
end,
copy = { 342938, 316099 },
auras = {
-- Azerite
cascading_calamity = {
id = 275378,
duration = 15,
max_stack = 1
}
}
},
vile_taint = {
id = 278350,
cast = 1.5,
cooldown = 20,
gcd = "spell",
spend = 1,
spendType = "soul_shards",
startsCombat = true,
texture = 1391774,
handler = function ()
applyDebuff( "target", "vile_taint" )
end,
},
-- Warlock - Kyrian - 312321 - scouring_tithe (Scouring Tithe)
scouring_tithe = {
id = 312321,
cast = 2,
cooldown = 40,
gcd = "spell",
spend = 0.02,
spendType = "mana",
startsCombat = true,
texture = 3565452,
toggle = "essences",
handler = function ()
applyDebuff( "target", "scouring_tithe" )
end,
auras = {
scouring_tithe = {
id = 312321,
duration = 18,
max_stack = 1,
},
-- Conduit
soul_tithe = {
id = 340238,
duration = 10,
max_stack = 1
},
-- Legendary
languishing_soul_detritus = {
id = 356255,
duration = 8,
max_stack = 1,
},
},
},
-- Warlock - Necrolord - 325289 - decimating_bolt (Decimating Bolt)
decimating_bolt = {
id = 325289,
cast = 2.5,
cooldown = 45,
gcd = "spell",
spend = 0.04,
spendType = "mana",
startsCombat = true,
texture = 3578232,
toggle = "essences",
indicator = function()
if active_enemies > 1 and settings.cycle and target.time_to_die > shortest_ttd then return "cycle" end
end,
handler = function ()
applyBuff( "decimating_bolt", nil, 3 )
if legendary.shard_of_annihilation.enabled then
applyBuff( "shard_of_annihilation" )
end
if soulbind.kevins_oozeling.enabled then applyBuff( "kevins_oozeling" ) end
end,
auras = {
decimating_bolt = {
id = 325299,
duration = 3600,
max_stack = 3,
},
shard_of_annihilation = {
id = 356342,
duration = 44,
max_stack = 1,
}
}
},
-- Warlock - Night Fae - 325640 - soul_rot (Soul Rot)
soul_rot = {
id = 325640,
cast = 1.5,
cooldown = 60,
gcd = "spell",
spend = 0.005,
spendType = "mana",
startsCombat = true,
texture = 3636850,
toggle = "essences",
handler = function ()
applyDebuff( "target", "soul_rot" )
active_dot.soul_rot = min( 4, active_enemies )
if legendary.decaying_soul_satchel.enabled then
applyBuff( "decaying_soul_satchel", nil, active_dot.soul_rot )
end
end,
auras = {
soul_rot = {
id = 325640,
duration = 8,
max_stack = 1
},
decaying_soul_satchel = {
id = 356369,
duration = 8,
max_stack = 4,
}
}
},
-- Warlock - Venthyr - 321792 - impending_catastrophe (Impending Catastrophe)
impending_catastrophe = {
id = 321792,
cast = 2,
cooldown = 60,
gcd = "spell",
spend = 0.04,
spendType = "mana",
startsCombat = true,
texture = 3565726,
toggle = "essences",
velocity = 30,
impact = function ()
applyDebuff( "target", "impending_catastrophe" )
end,
auras = {
impending_catastrophe = {
id = 322170,
duration = function () return 12 * ( 1 + conduit.catastrophic_origin.mod * 0.01 ) end,
max_stack = 1,
copy = "impending_catastrophe_dot"
},
}
},
} )
spec:RegisterSetting( "manage_ds_ticks", false, {
name = "Model |T136163:0|t Drain Soul Ticks",
desc = "If checked, the addon will expend |cFFFF0000more CPU|r determining when to break |T136163:0|t Drain Soul channels in favor of " ..
"other spells. This is generally not worth it, but is technically more accurate.",
type = "toggle",
width = "full"
} )
spec:RegisterSetting( "agony_macro", nil, {
name = "|T136139:0|t Agony Macro",
desc = "Using a macro makes it easier to apply your DOT effects to other targets without switching targets.",
type = "input",
width = "full",
multiline = true,
get = function () return "#showtooltip\n/use [@mouseover,harm,nodead][] " .. class.abilities.agony.name end,
set = function () end,
} )
spec:RegisterSetting( "corruption_macro", nil, {
name = "|T136118:0|t Corruption Macro",
desc = "Using a macro makes it easier to apply your DOT effects to other targets without switching targets.",
type = "input",
width = "full",
multiline = true,
get = function () return "#showtooltip\n/use [@mouseover,harm,nodead][] " .. class.abilities.corruption.name end,
set = function () end,
} )
spec:RegisterSetting( "sl_macro", nil, {
name = "|T136188:0|t Siphon Life Macro",
desc = "Using a macro makes it easier to apply your DOT effects to other targets without switching targets.",
type = "input",
width = "full",
multiline = true,
get = function () return "#showtooltip\n/use [@mouseover,harm,nodead][] " .. class.abilities.siphon_life.name end,
set = function () end,
} )
spec:RegisterOptions( {
enabled = true,
aoe = 3,
nameplates = false,
nameplateRange = 8,
damage = true,
damageExpiration = 6,
potion = "spectral_intellect",
package = "Affliction",
} )
spec:RegisterPack( "Affliction", 20220821, [[Hekili:v33cZTnosd(BX7uLI1ehhRhotM5IDvzsM92mFZRko7MVQU6SmffKf3qrQLpSJ3kN(TFD3aKeaeaeusE28vvQyBsGgan63DdWRhD9hU(QfbfSR)TXNnE8zVC8Oth9IZMmEY1xv8Wg21xTji8tb3c)ssWA4)F9YLXrHfrPj4REionybcI80YSq41Rkk2K)dp)53gvSQC(PHPRFEE06Y4aShHzbllW)o85xF18YO4I3LC9CJJ)OxaWCdleE8lohaB0IfmEBz5HYZIT38XGS40WpT9NFD5TL5fBVz8OtG)dG22FE7p)Mvbj3YY)HT)8Z2EZRbOSy7nxTHfhV9MFb61PYp)TS7GLX2B(1GBJcvEZ8mwWNcbqLWGogNcVF7nltH2(2SGiysCvAzmVhF4EOPimIzlXw9(GnfLzS6EvKU9M7tZGMeTC7npKw(e8LRJYZJsUD7nbqlGUMaRdeUfRcGFll9EoW)PKG5XmeOR3eGTPbrKV9M)4U)OQ3sZLC(ygCxAeUsItVNgO3gK9PBJdWbhhiypQi6zfbz3YaWE)ZHE82F)dqFl3WH1BstGTGCO55PRzk9)pYyB2EtyqCSySYylkdHxaB)Bklc47tfrRzCqDfoeCOGDAwaTaMfhH7EWKplIjauo87HfklGWvSWprRaS95vOO7ttEc8J5mC0dGgbn94GBHnNJgYh1Fpj(bCSX3a0Iqd3KXE2MY44QT6)jr(8xMxMbt3382CeCWMmdNuyNG9RLr3UQ4VOSzgSzdc4uc84dMNMNlAj8ZJtsXfqwq(kyebMPCX85VgZYxXzj(hPidcUXEvA8D0MFyamfJNH0iHej8coWJskyzzLBkGxXHZ7GNCBgWcT9MFJfMbT5x)iU2IsZIkEGJM4T8TcCugrHkr5cOpGFfzacJwdZee7(JPXyBlxU8uGtplDjm)U(QV5BKP5Ky(OxyIbeFrdti(x2yevFNoZO6B9LHu0RhpMsXa0hgt550HG5uaVdfdQaC)hGjvmYozuRjd(tKzvmMhegwbS8KPv06DLXf5)47B5Nc4qy3EEqXflHP5I01rj0((jrlVa35V8SbhTHvCAqC0DSbhr9)2SO1PrzSzPlNLheMfbmpStl3yaQp9INNxUEnqHaaX87lZzZIkyRpbTK4IcG0cHl0fGakTmFwi9BLcMgparEAmlyv(SCadYkMvWcxLe9VkzM7RXfdT65mMMxSmIXEHzqUSMIW87Vlilc7oF6UiTiFgSfU4HtUliUKDb2L7yWErbyOerJaqa2hKEEWTPjpO(OsalHaDwqTigObhFKyzKhTzfXNUSEY)LVi1DP3F5zdhCm(SnablSFmdL2b2QHKGNwerCWF5lva2uJedWqleealmInBwCNehLWMfU4IrNHy(Cu()mUCT8tB38zbPSlVyIzOVkOmXgLwBuuLQOF6ZSWYcK5KDhl7bUupu(e8FaOqnir5OCSGOyeeNwpcIzlxDN4zWyTG0tnBnQMs(56cn50aWc6eU8YlgHyaXgdlHTgKNE5eziSMRTAwgxzf2CIReGCW6OcILjdmhgK3LsmLOM2auHAoBtax4sGqpnxSnPGKK3eNMTGlZHeL8HtHUwMLb7ZnIhtH9G1r)BexrDSe1TWL38hxDQ8mnRmP9snbhNzRVxz9gMcslb6OttQMfdGoJcUVLDA1c(EyUVAGkQ5IrdSthsl9xlTuZftzyKt(eJu5Sk4oq4kSoVc03H7WOQI8G7QxEvQp4YvFFAXZF36naULeQ(MGIaum1MvSN)h8ja0YMzayWtkqdLDFeIKWPryAA8I07toTBIcXSCw(M4OIzKUZU70cwCWdadJOZ5D3dGNOOU5k7kKqaWfU4zzWVuZ5JpnQchmlSbfqcsuAMdjidhqqoFvq2IlNWB(DGUtGVh0n2aMk5xP3pdWKZqPbESOweaCESMLLcngQvF2YagiDSsu8Pki7V8L6TP6LFgBnmXYVC8zF5lh3QBPjSbw7ZReT60rNw3gXRgAcyf3N6bWg3gydXjUyvIMFS6HmFwJg3m7Zc2ja2RvVFq2mQ442svKWpF6byCtKEqcSKg6d6YerDpqwo6(EHQ8bUMruEOk3h8IWqVfvoy0hKIT(UxyKobQj0bP04hj3hYjr(KeQCUlGKdbctbIxNIkpbYNSUupdotmG66SQzaJBVXm0mJVTrq4alwYvjoKMCVd9Lqq1U9gOhgv9WNLGw0e4zNiutl58h6ec7ZfKxrKzoHCf9Ozcf(iGvaPzGfwBiTfTe94LIcp2UgB3C0AsmNuXAsdQL)Bs)2FAZNDs8uhkvT((6PoN((9SLGjIRiQhGkHfKHw2Hu43Msg2aQGtPaCqKLWpQn5bGEoZd6J0cdugnO(J6a3RR1BQYwyff2r9KeZT6KP782I9TA(u01wMxcWNoSM13oZUaIaZEKqivEWsbREn7VWswzxvGNodr44EvhZwR9Zb1(G9Xos(6(QhscTTY5UE8p4uep)34sO)RbmnHKQMIx22ECc5(tR38a4loi2)3ZwKeqHzc9UIJoJscXaKGy4vq3aWKuefJO7NKtXUAbmFoE0lrzOHPjOwJGLfmUtsdLXDgqtwSrLccZ5o4mgn44k9zmXSFwQyY3s)2Rg9cu0e7FvgTzdBr7E0RzzfBO(C0nB2bFc)nkEVYPhQJP7hrVgX4WrU)TPIekxH5H8pmHznUz9aN0ThS6yRf1J2S5WGvVYN8iGN(DKfOHZaJTjquhxYLTdcZEg68pHnhYrAOx9QSkEGno2TatJ2Mp4iliSHdp0iIoN)gSyB0l6Pe4NKxhfPk5VPCS)6G)jgzbs3BNksRqukEM3LofdACB7AOcIGIO4jHpesEGtrERzOOx2OlsUFIWTHYOtVxyj5vKp6enZembhe04MxWvmrHToSjWsi)hyQlj5gXmuAhqiX7liB(JeF5vuqk3EZVeHQ14O4G4CmE9ScsoBnQwKNG7447Ksa3(Gio)eP(emZivbumxjAmgIpz7qYnEGPatimRPfaQ3yokkzMyLU7JytOA7X4rMgk1cJ7MnbGH4ILIqZO6OfxpFg2TPYxoASm4n4zJ0c1IVpxaEpkBERj3JmUyKWt2iSLJkUry0dEYJAlsJhasEULAO2KjiX)A0ZgxZLCsddWKkTrVEEEACjg2wjyiphBOAmSmv31E10NDSjc3M4S1GrgAJKzmFDXTSH4ttb99SSte(ji74W9RyWAbZY358Lv7KTkLGqKFneys1S00Gp1sKMt5AuhpIMwFKgqkHD5GvJeZUzb24422SryrCfrnRMU1LOKM4khMONHctIKYb0E5RSl7N9YqzNmJGHPwCbURXTxUhlgMDYfQUGlT5(318IH2xK2MuZKmAnoLgzbxf2yudmzNhUzITdjnJzKHoaB4Akw)sqeuMKB1PhYmHUfcQyirtk5mGY9mkJkaCO7PNRn4oN6p1ElwuMrjk(vktgr2Mkcx9mIDbZklIedULjYNsqYdfRewBwqcmcJwgrzEloNDpT90jhfbwkXD1rY4Qvblqlq(P1ZZci32ejUPj0fvrYZOyOohZC5ScNtJ2mgFWAIs6cgLloTxdkSc)0RoE8Z4aT61K1(1kObohZ9U2FajEG2sr5cALnTKlLQCJlQ)8OBtWmAtEjZTwv4tljxpH95cZIpf(lxcTn6FtyxvpUQDrUrvaVcteBxe4jpRDlNNIDGP8c5LqrEZ0LHHr53IVgF5l0oGYZeBFt(YxKThY5MbUuXnnColwRRRA09Chs5rvqGSROmtyv1hcU5ClQunOOovKsBjZlZqjw3hLqe9hp(mPyoGEIWfKva7CWlGHkkmIcUlc7k4s2yWh6HDSnyZxwRHL4YXNnWaQuYiRVbrCvOiD31rPYKaeKMmxE9l5Pp(S)lsBIuSE2T1HpQSg29cYc5akWXSniuyjobPo41fvEn5dMdADUhIqSnYc5Sl5LKwuxiGUctNdVk9u504ZbMiuZdU1nRiD2Ii2R8PNhk2sFw)APt(BQlFkHRL5vv7aSb8wmai3sVLBq(7sy3fvWRSV3cMvNtSLbKNMFwSlLleqkNXO5PLcoqYi5fPcDGybfkRNIOZ5qrr3ood5UZejQ5JO6zYSf0eHJuUC6zcmw7guUzGHOB0dNE8kQbc58eo6q6aOf42HREw6LBhNK60G9Wjk5bSPWWQCHzoia)07eLniy4gv1GNixCG8nA9MixTD1KgC7(A1x94lI8HsfgMrlzSzlcN86IjdCAQYLtuw2sM7ix6HbPSlmioqPbpTvbDXFOVoA9iKtsWTI9o)FYE)S7zJ8Wmt8r13HppK6BOMdbMXySbgRs)MFG4O9moDTdcsBzjIjGvPHsY3O28QP8japUQ6PwRVq7YlMklxCqNq(rrkSdyBynCufO2C3gXgugVg5L6yETFvUNAVAI(SqnoMY2h4NGe)dWNpqZN4)CCNjpd4290RNodMYEl1amvBNeB0zahoq1wHbPRhBYvLACABxe)tzQQt)81C0L29P4oefjFyR4bbYNwATOy7GTvPgs9Rt2RM2o9UYXoN(yBWXgZXjXZo2YSdJAn9ayv9RzM4rNKJLFlL6UTSxsXGulFfyGQSgXJ0EVnStpug0TUGE4U2fNFMWNz7oTP6V25w9VRYc9ZnApP(K8XXJefmWxLELurDz2ZKQn3lmQQvMo3yCu6uG4RgDMp1n75E1QXyPKKSOmQXmvy(gZysj4VEfbRzRRPoYeKdzxghhTnyottxlMZRdHo52x9ZN2iEKEH5Lwf1(byh6CFq9poBqYRId8EsEyAzgo6fryqMKi51u2DH(rQdMsyQckKk2z9(8u9dI3c0aRL4zN7owEol2)EEB8dBwHUMfKNhToIFpb4F3ltcxbOEqJpStSikOinlhvWe(PyPS51jyyZHwHR87Icz(3nqTtkIVbH15SS7sJ6bklilCf8xHf5ZGTjwcq08a6FApgE8aloJfghTjVh9QiLn7tjmwo4JskfstV766SmymdYbZSVlThR1W081GHasBrCmhEA7uOmL9E6ctwwO2ezJuD0MnP6evAnaPCNhNMUWrBO3pBzz2dUAeldieuzkB1OEy7HthrBbyD5sk4wndJVWoPKQBRn(vzndqV6fglz7o9Z1uN93ft7RT2S36vgy)xIJpBFwJA9(rzrMxMWPrH)aMB5f9Fr(1((ioHJzfKw1SY5p0)v4l3Nv4l)tyfsMPIbRmBoQveKqUMLSdBLMpffEUqNUZluPLQ4yHCbp6MrMQV0x2DefUSvVApeAopgzVI)8Dan0xJdRL4RAj6L9EA4aggNoQXdVv4S73G3URYBVijBToeL3uDSVVWWLFqvvtZV(dmpkxoEqR9CXZCGpGwy6gqqeZV2BNxkoFuFOkMp3eedM92C(2fvIGwXgDY2BE7pkE1FJ8BP9c)P637dvhzrI7xS29j(C8ModRwQM2B5meCs6MlYzfrlpb9ajcNrMRGjBH0WXzHKYsTi92nfuuDTwLMMyglykP8svkW(CYiFdvgF8egQwUrvfd2sWkRu6kqXWmJ6yfpII)NVA8tLNx0G93GLoDnS0C9SGNDI6HeXrn50pfpDj3gNohpBr3dll86WjOKFwKefmevgaI6PDtAwrzsuvDQwd1F9J9cRE535QOvUnCb8Mp3ET9xJqKLqV02BQdbkvP(ajsuy0gX1deEJ6OFEzmpf9W6RwNNxAkagk5banAPJfa(cFGNbZkSaUx6d4SRd3cuNwFGtiAIn4MH4EiruTpKSMtqUq66Cs)C6G9dpzfPan)91NTPF04K1GahP4pqmddQNNYsTncndX(rbs(iN7YZ6C9F1pvV4r5V2x8uRRLH3VzSQGYEGeCJs1aBxsYV0clWUzQHz6Fh2Kn1yh80(kZD2lZsMQECLrbSbTo3bCzTQo(6wiBGQS6dMa1XFRvrQ8RGh9jzKZJtM0rKYfHMxzDUhPIIxkJuL9YOc2U(KRHz3srDGpNgUEmN35SNXpbAMlpsCBFIOiOR1JYlx6B5Y3X7coSkAJwW4hlhqpcVEm5LSoDx3fcdjvlUjLRNth2L5y58n90ZPZ(lsaqDjQsjomqL4DUgQHSGLxije6dJ)UH9KQ7yxvaPRct90Z520(6fCdardq(13lSnjVctW(CrwqJbEb0bCP62UcjcWc0pItf05oUazlBHi(wUTqEB)s31J6ouHP9Oos1Wzk3VE8tglh1H6D7ICxovy(rm)lifPI1LlWAfvJawklNMXR1Y0nwZoDRjPRUPkfVRwRPWOTNzQLw03iF7kUvRQ6BDzlAgb4BgoRVOgnNEZzRkxhKKgTO6kvd2FEwZEJWNdXSV3UxmHlYnPonPrex3BVIFRrs3MPOS27z4qDhtWBHg9iUrh7KMZysxLZzR1EA2GLooRkotv7RM81xcHTS8)kEAAj515Sl0kz28V2tgFUJCXRysGw(jWktbm)pVaKIEBuSLo12vSWGSC0hSL4PGjdKUpdn1yjZxaaZ)WSsU4Y)vjihVCn4ZMAwc7ec0DAkM1Rfr3Hx)LZXl9yp7E6DSSLC)AMfKaBDZcXtyNN9gTmCDkgIpw4NMTPSGFDr6)SFDqyWCWWY8vmWB11G3yH(21LXb8l415bffXEpI3h8j0s)CyllnzHV9I2HkWrBblFtGCIyD3rPCsopyH)y2uytmk)tK)9aTjDOM9SRRsZsW(DxqCQ3ZtCxeVCibfr5R9TtGfzGfwRyblQMNjb3gVmWXOAknN6TXq6sBbgPeHYpS2yuM4Nz38skMxBVz7)pWCtWCQ)7F)984n9lLb4jlhu()UNGQ(cttaYFYu8Ivrc)6qdOwTMvqxk4vJFv8uKUbn1I)mD8tb()QRlerCyp(4rFRJBqKNk)A7cduBNE8K0ERE0Rgo8Iroxjp1waLttyvldXJoDeyVbLz)WbQpQYQ5H72qvCFQ(qnU9qnEFgk1QiOA0oQhlnmTvh1J5h0(6TLokefFwakTPA(B82qSj0skRzRx0HoA)OV10iqKC1VqN2hi4m3tyS6SNxFfWtMdifXxSJxm67U(Q7dYqFIZV(Qp(63)BV73(F)da79nFanDnAnNBNCW(jgWJpbTMgGFgYNZVW5dkbhM4(GZVl1X7TLFHU3Mg)d0nDFLCHN0qk8F)eUaI6hvWF2XJ)8W6UpXs3hBO7JB39P73OBR7Do6B)5oWRALGt)WPF)pGUKiKlJnOsnY267p6)p40tRWH()()I)Haa9ynkNmvSgKJoZlyQwrrMbyNRDfLp9BLpASxttdA7DU4p3lOAv98oIhQsRxprb60KCxbAiif)DL3air5ijAA9(xvbK1aO(b2Gqlw6EodAXt3Z(3IRCp7F)XaNVZZGojkwWwgug3tAIDy(GHl(N(9FPJfwZP(UgwspYg65LhQPZ33FX3t9O7oeFl39r7cRMS6Jr7lNYO9LuFulkdX6nyEy9f0xdzViqTWlBbOxCOa03DqiXAbMDE(OtSUJZNw08748z8(kDC8(sZmUfBJhaqXMT9LVzY(Y3mzFrIt0j33nQIjhgI9jhgA0j7YgRtaSBZJPN1)5Hz9dtBjvQBiPAGV(guDAiQbrZtCmD6uTEqk7j9sL(Uqb701fp6)HXeN9q33ezaSlya3IK7gaMjZgFWiyhVdIgTajDs)hlk3Q8A0pY3DyDQU86F)nJNgTd7DQayFxk7eNWOdjNW4wgl1xaOZkTJeB7H9bvuRVBDLp6JMSv5ZLfs8D9v0VrFHBLJYa8GFJ(05kG41)y13hxTmvD9vCq2(ffx)BJncbRjTQbw2Bca1jgHQ9Gx3awhTbG7uBW1u(TuaQXgaq8CJq0CkVAaOL3dW7fgHN1KG1as7nbG63zeQgYmwd8m9sasV0iK0suwdu0FbaHV3ieuZzwda0Eo0)rNzMOf)B50Njr226viymt7RNmTgO06niqmt(BiwBuRntwRKmTMXt9Xy3nt9QKwnP9pLhJD3mPQ1i4r9HihRaztI1KHd2SVtUz15wtVvVuby1PxtTzfW(v7aSBsyv6gqkcRObKvH8h)T4s4hhdcjbHIBV5B3EJ9mKT9MHBV5PMAQJuNBTp6zoZrl1ZIg1u4FxanL)vcplAdFPzk3J0cEMqGRwsomjA2l8LuSJQs902Bg065nvU8q5PHu6BmjgVFZGXwMbJ9zguCFQjb(EndoI2T6pMG(3x(c1Bny49APggUZQN8swnVjMuk51Q2uo4OjRLm3jVAnLfoF7lNRW8ORX6ynNE1SnDbvAE1BOAIaJeoXLxPL4k7gwjFZeizjK8tTAsL(9tGKMF93y1aklKsnA4m9ARMn58IlObQUBMvtOuUpdAGM6JTAWu7R1Ggqy4DwnrY6vCqd4S3eRMljFu1Lq)Yp1QHsTsHPdBIutnPdRECC7g0m)C1ioFG2rd2eJGXf7vGIoG4pkGee1(qctIsSEqH3EZR2EZlKfPOFOHv7VZdoSdGrE9ZVmNXxPDqI1Eycx(LXDCd841K36gNCiWn49T9Hd5ybA7d2P9Q2GiSAXL6MnDiqrFLt(0EnBqQSS(ezlqpe4NxEiXpMb2EHF0xYguRuJEmF2gpeyPPhsSKzGTxyjlRCHrmYNaRAr31wmwFt2O5v3y5wvFv2O1OjYnIFx2O1IP(4b55E5n6l8XnZw67B29pYe6gdEgEaVq0sJgrTZfgpuBZQ0PYHrTzancWuVYcUw3)36EAq)PY0ueuqtNohrxiIUJLPBTCFjqKCJoRIaQZwF52BoVxTE85cgaJxUynZ3HnikJ8iM0E2Gu8eJ0XzAYJPGU2PMPGFOJZR2zmDdYrTykh72SnZBIjeL2jIWKYHhv6MZ7dHWJoztLOztkbE8OuKhvfjqQxJDTy2RU7tCZS3(kKrOiDGViYwqqYdg8XU5RSDJYSlZcdWrcB18s3SzDD5YSlZmhWt2F2wnYndNLBIMDzc2gmYUNv9UkVXOQMRLM88nmqRvCA4NCQjNDhq2oBDWTysbARm34kf7CZxEcAwpP)kodsnMRMMHHeycGiyDurAz(SqEQowKEA5MMXq7q6AsAGsiw5N59C2Ma(NBioC45rtK4xPpNp4jYNoHTF40T38MMJ(o)dXskaZ1r)Bugc1r6u9xDLoCAZCmRmrfniHRK1O024Vb0NlFtF(zueFPVJWJr2aFubOSNuLX7RneXffS4RLWA5vFkKQc63C2QG7IsZoLo(71F1VWVEqvyQQ7(g(jx(9Pfp)DRRVxAEtJo4NB6CDR(zZw5lMTN0EMs9GbJf9cwTchIH4bP4ZbjCmv7oqM0vIVPZBs)MM664AJovmGFfjXp(4C20MoB4E5MENGIr5s2UHwPVm5QPIUOD0Umr(R4kgpi7TIWlTZPBHrlN1UKhhdH3vwd9TB39KYeqDdRFVhbh3tOp2m0hQ5SNSBM9a30HJO9fr1TFThmSwpgk3OW91)6(IYDCPp0FeUtGDir3EpqUr29Y9dFXOUDHOpOtN(5CWWL(nk2qKEkIvpTufgYtGnJLuvQB7w1t(7fx86u0ojG1itXwTu8kmAGOTZKxNk36qyI4K1jnWUf5vUEvyiDgktB824QIxLaNrJg4ZFWyk80)DIWwnPpQUy5xX(Cb9vWJUilex0rOTIfU2kmhprzX0EQw3BkNX1bvWIrakSf9IF0I0sfnYMTF5RUz)brCFNMz5OnAl6HACTkXHTWqrgPqKxFDJTG(m6YcYqhqqUZBtPjcyix6wPVnNnxZJWCto)J(sbRUPFKx777w0YpANyr62UGPhCYbFicBwqDr44To3PTOEQIMuHHYnR23(MO03sEPpxxwrcz(5blfYhlv)uNRh9dxbqRWqHTTJbRCV9FAOjCuHHsNRQvgMuA40REij0gwLhqG2Fv)10AP6vBzlxB5x7K)KihQBV53RRRnmqj8TQOKW018Dp(x6AX3Y5OINKx)5N)4rVCBZhMzXvximEd9WBmUs86aB7MZFu1owDZALby12)IgX9oRJpAZsp(egM7YczSnZ7wmYJ3YWjbwrvbxUteKsXWIt)PFdesFLNjLdCs2CfbbuODsQJML(LP7bkSv22tSCFJsy3jpA7gfv1U6oHW)D(9qyf2ag8JbUX4sUoyqjYZWyjsBld3kUR(0VDCTPk2HEjho2Yve15(WqjxBFuWP2d5JdVga27U4ogR7LZoQL7j5vuI164exTORd(NyWkrtUCz)KXO56Jbawm3YC8EgAnTZJTv9v8m(0z(LMcnr(ZyhUsqWQKPakTK6PsWAX706RyRU(s8MKKCZ6k6R4hXgmbTcGMbClB5gGqvdT0TolkBI)zWLFJEI9KGeVVGEYpsYSUIsXu9xpDABoigVYMMZkiDE1B34CG7tlUNNuYVWvd2Sj(bARAcEODQwj5N2rUqglBQOX4OQyrT1p4VvTQ(Z(lHYTBevNtfPeYTFtKA3ESKVRPoPeWvH9e2ECRGwlQ2xZlVHA2H4kcrGhw1ZlPcDbNp2nMqmSwIsbLQfrGN09jSR0wkHLSKSXX20)lN(uptFRnMC7PQ4rOazgRRlOgcsckAnnDqJZDo6zKOu3CC0oKdgHHDrupwpfyO4bzbdYYoW)A0Zgxlq7KgzvtQmQ61ZZtJlXCq(gfMJj7w07EDR7G8terbqoSa8ROx80jEoF6uBx475qLlwmGUMajrIHGCq0doPDbng0PQgZnMiSM4mMDFKMgj4ThCo46eX2ywBnoBA77eS0UIy1vIHhQ0GFLMNwN1rukEeBr)J)Hwek80)upDbTdzwKFADgiU(nR6Di70MehKaO0941ruYMyRKQTfTJ)UAml4ejs0m3ZpUv43jgXui4wGNxWWk(OYqnS(7jdY9eZil4bo81uISLGiysrUrRC9tlLMTWdQYqIpB19k)tAdezS(e7v9r9YWZ5IFl4N6QvvFjUj5VktxlrWzIU1rAL(rr4QNrciIOB4SYC8gQvCH6N8qXkHVAfKGZWOLr4cb)QgDpsd4Pcpe20KPZQsZ8LyC1EUJRYycHCmr(9SQsy5uPlR4tLmvtWb78MpUYZAFZ5e)0nmr3Qj)uurCKTv7W1mj5YLqaE5gx8I54jQcaeffnUkirmVifHjSpxywZIiEAL0NucAFxncj1HqRr3jQkQ(UUNapIsVUD1DyR2k8u5qvtBlXwoh0D6ypcgBFAbQ2WX202CBUOaBgFUt7UiUdj143t(eYBDvJUNhrkEymf7Ev5FmHCnRiLVBFlAwd)A3yz9xZb(E88Ym6ZFquYc67MbMo46GCIU8ZLtxSc1pLddvuyeR6BYvfCjCcFOvIgAN46boJfQi70dmUFOAKoI4Tfek3i(FTg7QhQpuFfj1d5pYLrDsrjeF2)Lq9DTj79ef0hteg6p(WMtd7eHiQnXSLMuerpbPl5mB51eU50N3avbb5M)WUGcPeFjOIkmiYVlvMoYlQI8bV1Ypwu121QVL(aLq4y)G0FMsEMQ7auBfNMRonBegimTfJm(3GaUN0k0pIVTkIWhLxvZNavWBX42El9wUNCVlHDxe5apgQC6lvnivkGIM0NfKk5cfoYftX80sHaiYlTfPcJp4FqOAYGlXRYHIIfzikoQESNTGg6k0m6y2zs7fTBy5gopO9OWs8FtTzYT3U9p1wCcBfGsPp1kMJxX0oJ)vpJuJYi2r8yMA9WMzoEmDVASzbLs8qmbpAU)ignelZxB2e08fTrpobg)Y20WYk)D)qqr3QXLKNFtj1IgA))r(qHOlaXWPHB63lh)CjRZvBh8NGZTHPRNh0XrbRoclNv5h2g8A2mo6ow1dOjnEkKtXlkG0LZYdG(dYczkfn)swmWNSokP(S)ReRFHJyBy6b8389naO0GglOpO9SyP6NkUkLaWj5RwxnSW2DqaqjWcwLduXHzyH2XcxLe9VkL4yT2IcpoDqMryTuRySz4aOCqGKzfuqE68oDFDDijrlukmJ1uasVNKKA(vgfgw3qLGlyuwGuW31cWCfyg2ltx8m(bk33lO)GZO4ZGysBgiBkTtssJOteJqGMH0DmlifxrxqNMfm73ZcHn)rNHJOcRSPuHXl5sx6p0z6XZ)I(H2XyAMvgNoZjNRtSOHiB6PlP(e6o3Kak2K2pcb94jU)vJ4FgZ3(4mK14L2jdLJ2OL8cVSARDaxTBVvNz4mmiHEQtguNYNpQl7ygC4sFPbZanpDTzZwlJzBlE(vvjlrmP55IVQg5mAYLnlU8y0qrzt1nYTEX7XyBp3GDPEz)T12Mt)gfTQsXinIBUBJGakly9gGhrQBQKrDTIEfPwWewQv12RAaSSdUs66vY)CRcCxzbDOZcBRknwjaMgvtixBq2QyosOApcZPNze6rumDTDlhez1EKTJ)el)DlQlp2CGkv27Sf35VkwGEsVBO(69i1wESc)pAg6AC6uPULDCgQ7Xk7WMkoRftTx5oRv196vVnDuCTwdT9(qvzxByNwP5nnE)fS36e26OElX5z7Ct1mqgIBARISufAgT8UdR2CpE(Ct4iTg8cM213PxjlUHJ1YD0C4)KmPqXP5xDrvzmRBxwLTSsUH70anhvd4H2ObhLSxhXH(IMldMAXrUJiD7arFUZazlnsto3QxHscQAI5FHHI)RQz)jeutEf(9)GcQ5y174khb1KeLRhGJQVUC5TAEE7OHySKJ)Fy4Rj(IUQV6n2PRa7wEZQyILIhFMFNZIv9sjR68iyH6IW0Gt7a7jDiXSCBwhTSlzBk5U7dc9HyEVJUnP5szrK87ROnc80urBPNW)S1tV6Vrx)wMUkGjRlSUhmdltORVQRZWs9oMpgbETH45zt)KFhLBktIIuq2uenv5zmpnnrP621Zv8b4SCB76SuWSRvWwyjDW)YXRw9nv3Fmlb1xPalQUDjA3ZAC3sEQ6c4AdHEYpS7FdqGuE22KfLMrfpaE4EQNDiMUj7TKlI3gNohp1E3diSfyOXk5NYp(6INWxrP7Ix77Ljrvf)Anu)1p2AVHyP(UgnQ2RKIBdxCkLmAdibN30p)1ieplSSEB1Twqo)CyauUrHrBeEgKUS9jf7u7x(RsRLwxLc04X33oRzxX4fiR1AK31fiRJb8foVnwTM6Hu73gRogSx66Qn1wiWY7(Qn1XqoT77ju7xGeDFo4ExLuMniftgVshevedjB9euaestPF63O(LGIHbE67Rp6HkMAku9ODhjoq(gOxtHIJqRzfy(iBMN7ljlaAF5m2koB2AR)yWR(PA0hQXYo6JADLwpdlAZwe1bQ0Eeu6gQDPyuhFAIsZDSo60mgoZDTPOMJ7CR4wOoagp9CvGS(gw0XHt2QXrANBk1liXwrXqfGDFoSutHH1Z5QB9EVVrvu9bhx68MWv8Pg5n3A8cuuCU7A3gtgJ4shxROIy4sbuFMh58iKkDKeB5G5H5mI2ranDF(x)7uHnZOcBV(aTIblsrhUphs2h1LvRWxz9WS6M08kZLJjsQnru)41gsXR08B5AB3EdPS54Ofm(r3cu5ZJKf)ybGuUXHWsGQ64KY1ZPdw1CSY9ME655iCrcrQlrvwXbduzCb3KOcwEHK44pm(7g6Gs)y)kDYUkC2tpxumLTc(LF4ZxVyre(BOnR)67fMZMxH7yFUilOXZc(bT6UGOyCuqsoavXI40CDsFj2EKDnbFl38zftE9Tct2ZsC1h8VLsx1AicLdqGveTOKt5Ntj(veahFJMkPWr6pZMPOeQQVsD(8li3GIRnlWssvJ5rkWLk7qYz41Dqd7tUGDC8CncgTdBSDDNUIKXal5RwtZCRdqBv7KJEOhbeC2QY1bjPrlOc1Rzk6r4gv9xREy3QDOl(hcaGeyCiqZFBEzyYHCG44znegchZfyjp8bFcfqdB(wyLf5VNuJ)Ii5lVfyhWp7QjmX557EgoBWYGKKIGMgti5R1JsTUXN8OW26SQAAk1hJD96WwrHkRJZ41KVIc2zr1PV8RMzKX9PMTXIQZZOQJZgJ)kgC1YIv4hcPRIw)g6jx)))d]] )
end