5 01 2010

Modified Ajantis Shadow Beacon, uses Skull/X/Square marks instead of the defaults.

-- master frame
local sb = CreateFrame("Frame")
local markClearFrame = CreateFrame("Frame")

-- constants
local SPELLS = { [64465] = true, }
local NAMES = { ["Marked Immortal Guardian"] = true, }

-- variables
local lastIconIndex = 9

-- mobs tracking
local guids = { }
local ignoreGuids = { }

-- loop and timer control
local nextCheckTime = nil
local lastBeaconBatchTime = nil


-- mark clearing control
local markToClear = 8
local nextMarkCheckTime = nil


-- Main mark clearing loop.
local function ClearAllMarksLoop()
if nextMarkCheckTime ~= nil then
local curTime = GetTime()
local abort = nil


if curTime >= nextMarkCheckTime then
if markToClear == 6 then
markToClear = 0
abort = true
end

SetRaidTarget("player", markToClear)

if abort then
nextMarkCheckTime = nil
markToClear = 8
markClearFrame:SetScript("OnUpdate", nil)
else
markToClear = markToClear + 1

if markToClear == 6 then
nextMarkCheckTime = curTime + 0.5
else
nextMarkCheckTime = curTime + 0.2
end
end
end
end
end


-- Starts the mark clearing loop.
function ClearAllMarks()
markToClear = 8
nextMarkCheckTime = GetTime()
markClearFrame:SetScript("OnUpdate", ClearAllMarksLoop)
end


-- Gets the next icon index to mark a mob with.
local function GetNextAvailableIcon()
if lastIconIndex == 6 then
lastIconIndex = 9
end

lastIconIndex = lastIconIndex - 1

return lastIconIndex
end


-- Marks the supplied unit.
local function MarkUnit(unit)
if UnitExists(unit) then
local guid = UnitGUID(unit)


SetRaidTarget(unit, GetNextAvailableIcon())
ignoreGuids[guid] = true
end
end

-- Checks to see if we want to mark this unitId, by
-- checking to see if it's a known GUID from the
-- combat log, if it's name matches something in our
-- list of markable mobs, or if it has the Shadow
-- Beacon buff. Returns true if we are interested
-- in the mob, nil otherwise.
local function IsMobOfInterest(unitId)
local rc


if UnitExists(unitId) then
local name = UnitName(unitId)
local guid = UnitGUID(unitId)


if not ignoreGuids[guid] then
if guids[guid] then
rc = true

elseif NAMES[name] then
rc = true

else
for spellId, _ in pairs(SPELLS) do
local spellName = GetSpellInfo(spellId)


if spellName then
if UnitBuff(unitId, spellName) then
rc = true
break
end
end
end
end
end
end

return rc
end


-- Checks the supplied unitId to see if it matches the
-- supplied GUID. If it does, this function ensures
-- that mob has one of the acceptable Shadow Beacon
-- marks. If the mob doesn't yet have an allowed
-- mark, it marks it up with the next usable mark.
-- Returns true if the mob matched the GUID and has
-- a mark, nil otherwise.
local function MarkMobByUnitIfGUID(unitId, guid)
local rc


if UnitExists(unitId) then
if UnitGUID(unitId) == guid then
local curIcon = GetRaidTargetIndex(unitId) or 0


-- only mark up if it doesn't already
-- have one of the five marks we use
if curIcon < 6 or curIcon > 8 then
MarkUnit(unitId)
end

rc = true
end
end

return rc
end


-- Scans all available targets to see if any of them match
-- the supplied GUID. If that mob is found, this function
-- ensures it is marked with one of the acceptable Shadow
-- Beacon marks. Returns true if the mob was found and
-- is (or was caused to be) marked, nil otherwise.
local function MarkMobByGUIDFromRaidTargets(guid)
local rc


for i = 1, 40 do
local unitId = "raid"..i.."target"

if MarkMobByUnitIfGUID(unitId, guid) then
rc = true
break
end
end

return rc
end


-- Attempts to mark up the mob with the supplied GUID, and
-- if it can't be found, the GUID is put in a list to be
-- scanned on a 100ms timer so it will be marked ASAP.
local function RecordMobByGUID(guid)
if not MarkMobByGUIDFromRaidTargets(guid) then
guids[guid] = true
end
end


-- Detect Yogg-Saron casting Shadow Beacon and find out which mob he cast it on.
local function HandleCombatLog(timeStamp, event, sourceGuid, sourceName, sourceFlags, destGuid, destName, destFlags, spellId)
if event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_REFRESH" then
if SPELLS[spellId] then
-- Activate the mouseover timer.
nextCheckTime = GetTime()

-- If this is a new round of Beacons, tell the player
-- to start going nuts with the mouseovers.
if lastBeaconBatchTime == nil then
lastBeaconBatchTime = GetTime()
UIErrorsFrame:AddMessage("Shadow Beacon cast - start mousing over the elephants!")
PlaySoundFile(("Interface\\AddOns\\AjantisShadowBeacon\\aoogah.ogg"))
end

-- Record this mob as one of interest.
RecordMobByGUID(destGuid)
end
end
end


-- Forgets we ever did anything.
local function Reset(removeIgnored)
guids = { }
nextCheckTime = nil
lastIconIndex = 9
lastBeaconBatchTime = nil
ClearAllMarks()

ignoreGuids = { }
end


-- The timer loop for marking mobs that weren't being
-- targeted by someone at the time the Beacon was cast.
-- It tracks mouseovers until all mobs that are known
-- to be of interest are marked up.
sb:SetScript("OnUpdate", function(f, event, ...)
local curTime = GetTime()


-- Reset everything if the last 'batch' of Shadow Beacons sent out was long enough ago.
if lastBeaconBatchTime ~= nil and curTime - lastBeaconBatchTime >= 31 then
Reset()
else
-- Main mouseover loop to check the current mouseover unit
-- to see if it's in need of a mark.
if nextCheckTime ~= nil and curTime >= nextCheckTime then
if IsMobOfInterest("mouseover") then
local curGuid = UnitGUID("mouseover")
local curIcon = GetRaidTargetIndex("mouseover") or 0


-- Only mark up if it doesn't already
-- have one of the five marks we use.
if curIcon < 6 or curIcon > 8 then
MarkUnit("mouseover")
end

-- Done marking this mob, forget about it now.
guids[curGuid] = nil
end

nextCheckTime = curTime + 0.15
end
end
end)


-- Hook into and handle the various events.
sb:SetScript("OnEvent", function(f, event, ...)
if event == "COMBAT_LOG_EVENT_UNFILTERED" then
HandleCombatLog(...)

elseif event == "PLAYER_REGEN_DISABLED" then
Reset(true)

elseif event == "ZONE_CHANGED_NEW_AREA" then
Reset(true)

elseif event == "ZONE_CHANGED" then
Reset(true)

end
end)

sb:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
sb:RegisterEvent("PLAYER_REGEN_DISABLED")
sb:RegisterEvent("ZONE_CHANGED_NEW_AREA")
sb:RegisterEvent("ZONE_CHANGED")





US Phone Number Regular Expression

30 10 2008

Here’s a regex for validating/parsing USA-format phone numbers.

/^(?:(\d)[ \-\.]?)?(?:\(?(\d{3})\)?[ \-\.])?(\d{3})[ \-\.](\d{4})(?: ?x?(\d+))?$/

Try copy and pasting it in Rubular.

Capture Groups:
0: “1″ prefix, if included
1: Area code, if included
2: Prefix
3: Line Number
4: Extension, if included

It allows for a handful of formats as well. You may use dashes, dots, spaces or even nothing as separators, parentheses around area code are optional. Extension may be defined as simply another segment, or prefixed with “x”.

Examples that all work
155555555555555
1.555.555.5555 5555
(555) 555-5555 x5555
555-5555

Simple validation can be performed just by checking if it matches, more robust validation can be performed by validating each capture group.





Stack Overflow

17 10 2008

I just signed up on Stack Overflow, a programming QA site with a strong basis on community. It’s the most addicting website I’ve used since Facebook. Users ask questions and they appear on the main page in a feed showing the question and how many votes the question has in a fashion similar to digg.com. People then have the opportunity to respond, and each response may be voted on as helpful or not.

Users earn reputation points by asking questions, providing answers, and receiving votes. Users may also earn “Badges” by doing other tasks like filling out their profile, or providing a very good answer to a long-outdated question.

If you’re a developer, you owe it to yourself to check out Stack Overflow.





Intel’s Tiny Forbidden City

14 10 2008

Coincidence?





Closure vs. First-Class Function

8 10 2008

I said I wasn’t going to post anymore on this page, but this has been bugging me. Since this latest dynamic-language trend has been going on, people have been throwing around the word ‘closure’ like a Swedish meatball in a food fight.

A first-class function is a function that acts as an object or variable. They are sometimes called lambdas, anonymous functions, or procs. A closure is a special type of anonymous function that has access to external variables not passed in as arguments. In most cases with the popular dynamic languages (Javascript, Ruby, Groovy, etc…) first-class functions are indeed closures, but I believe that it is less important that they are closures as they are first-class functions.

To help clarify, in Javascript:

var lambda = function(x) {  return x + 2; };


This is an example of a first-class function. Technically it is also a closure, but the fact that it is is unimportant because it doesn’t reference and variable outside its scope.

var y = 35;
var closure = function(x) { return x+y; };


This time it IS important to call this function a closure (though it is also an anonymous function, lambda, etc…) because it references variable ‘y’ which is defined outside the scope of the function.

In Ruby a ‘block’ is a special type of anonymous function that is passed to another function as an argument. Because they have access to their parent scope’s variables, they are closures, but they are more importantly blocks. So call them that. Using ‘closure’ all the time just adds confusion as to what a closure really is.

Ruby block example:

['one', 'two', 'three'].each {|it| puts it }

The “{|it| puts it}” part is the block. It is not important that it is a closure, again, because it doesn’t reference external variables.

This is really a bunch of hot air, but I believe that it’s very important, especially when dealing with very technical subjects, to use the most appropriate nomenclature. Unless you’re referencing the fact that a lambda (etc..) is referencing external variables, don’t call it a closure.





You are now being redirected…

7 10 2008

I’m abandoning this blog. Yep, I just started it, but I can’t be happy unless I’m hosting things myself. So I’m preparing to launch http://www.alexeibroner.com/ and http://www.lex-machina.com/ to host my new blogs. I’ll be in the woodshed making things work for a couple more weeks and then I’ll be back up at the new addresses.

What’s to come? An article on RESTful architecture for PHP and a preview of my REST server framework (oh god, that’s terrible news… not another web framework!). The good news? It’s easier to use than Rails (really!), and will be available for PHP with ports to Ruby and Java/Groovy in the works (and possibly Python as well).





33 year old high school cheerleader

15 09 2008

Only in Wisconsin:
via Yahoo.

Isn’t that cute? She just wanted to be a cheerleader. While public humiliation is one thing, I think pressing charges is a bit extreme. I mean; Who doesn’t want to be a high school cheerleader?

Thanks for the link Charles.








Follow

Get every new post delivered to your Inbox.