Powerful Presentations

| | Comments (0) | TrackBacks (0)

I'm doing a presentation for ALE Central this Thursday

Here's the blurb

In our professional lives we often spend a great deal of time in one sort of presentation or another. A PowerPoint slide show for work, a story to our children at bedtime, "selling" your boss on your next big idea, or simply "selling" yourself as an entrepreneur.

A properly created presentation can be extremely powerful. It can mean the difference between getting that new contract with the Johnson firm and spending the next four months trying to find new customers. Perhaps your sub-par presentation is all that's keeping your small business from catching the eye of some big venture capital firm.

Presentations are a big part of being involved in the Open Source movement. Conferences, user group meetings, etc. Being a proponent of open source gives us quite a few opportunities to present.

Come an learn how a proper presentation is more than "not putting everybody to sleep". We will cover everything from preparation to handouts, PowerPoint decks to no slides whatsoever, handing "that guy in the second row" to "Wowing the room. You might even learn what a "bathroom review" is.

I promise you won't be disappointed.

And here's the important stuff

Date and Time

Thurs April 17th 7:30pm to ~9:30pm

Location

Gambrell Hall Classroom 1C

Emory University School of Law
1301 Clifton Road
Atlanta, GA 30322

Great Quote -- Sir Ken Robinson

| | Comments (0) | TrackBacks (0)

I had a great idea

I've been a big fan of the TED talks for a while now and listening to them just inspired me to do something new.

Every so often I will post to this blog one of the great quotes I've stumbled across during my day.

Sir Ken Robinson on creativity

Taken from his TED Talk.

If you are not prepared to be wrong; you'll never come up with anything original

Hope you enjoy this new feature of my blog.

EDIT: 2008-03-03 14:00

Fixed my links. Sorry

Good "Hack Music"?

| | Comments (7) | TrackBacks (0)

I work in an office with four other people. This is a good thing when it comes to communicating and working together. However it can be a bit detrimental when it comes to entering into "The Zone".

To combat this, I've been listening to music through headphones... There is a bit of a problem with the solution I have noticed, not all music is conducive to entering "the zone".

Here's a list of artists whom I've decided are great for "Hack Music". Artists whose music is great for reducing ambient noise, while not distracting you too much.

  • Muse
  • Blue Man Group
  • Thievery Corporation
  • MC 900ft Jesus
  • Daft Punk
  • Basement Jaxx

What is your favorite "hack music"? Post a comment and we'll make a big list for everyone's enjoyment.

I've just racked and installed my newest toy at the datacenter: a Cisco Catalyst 4948 switch .

Prior to working here I have never had the experience of working with a Cisco switch other than to plug myself into it and run on the network it provides.

I'm keeping this log to document how I've set up my switch.

Let's start out with what I've done up to this point.

Using Virt-clone

| | Comments (0) | TrackBacks (0)
Using the libvirt tool virt-clone is pretty simple to make a new guest image.

virt-clone -o ORIGINAL_GUEST -n NEW_GUEST_NAME -f /new/guest/disk/file
There's not much more to it.  Virt-clone takes care of all the unique stuff (uuid, mac address, etc).

I am a genious (SIC)

| | Comments (0) | TrackBacks (0)
I have two Debian servers, One is the old one, running on hardware that dell is no longer supporting (without us shelling out again) in a couple months. The other -- the new one-- is a virtual instance I have just installed on top of Citrix XenServer. Both are running Debian 4.0 "Etch". 

The application we have running on the old server has quite a few dependencies, and the Operating system hasn't been re-installed in quite some time. As a matter of fact, it is running an image which was based off an image which was based off an image.  In other words, I needed a quick and dirty way of installing all the packages which are needed on the new server, without using the old image.

Here's what I did:

First, on both servers I made a list of the packages which were installed. I did this by running the command:
root@oldhost # dpkg -l > packages.old
and on the new server:
root@newserver # dpkg -l > packages.new
I then combined the lists using text tools such as 'cat' 'sort' 'uniq' etc...
Then I used vimdiff to find the differences between the two servers and make choices as to which packages I wanted installed.  All in all I ended up with a third list which was my cleaned list of packages.

After copying the clean list to the new server, I ran this command:
perl-01:/tmp# for i in `cat packages.final` ; do dpkg -l $i &>/dev/null && echo "found package: $i, doing nothing" || apt-get install $i; done

This command will install a package if it's not currently on the system, and output "found package $foo, doing nothing" if it is already installed. You have only to sit at the prompt and answer any of the dpkg-configure questions which may pop up.

Cool, no?

my dream home

| | Comments (0) | TrackBacks (0)

I was reading on of my favorite web comics this morning and found this gem:



Your home is a

Futuristic Headquarters

Your kitchen consists of dilithium-powered food replicators, manned by obedient robot slaves, who are sure to never, ever rebel. I mean, it's preposterous to even consider it. There's a pantry stocked with beef jerky. Oh, and deer jerky. Your master bedroom has an on-call masseuse and sports therapist. Your study This includes all Star Wars novels cross-referenced by incongruities. One of your garages contains a life-sized X-Wing fighter, and KITT. (KITT was a gift from a well-meaning uncle.)

Your home also includes a robot repair bay, where your mechanized servants are routinely fitted with new restraining bolts. (It's just a precaution.) Your guests enjoy your animatronic replica of the cantina at Mos Eisley. Outside is your radio telescope, listening constantly for alien transmissions. Especially invaders. They'll come eventually, even if nobody believes you. (Nobody does.)

Below is a snippet of the blueprints:


Find YOUR Dream Home!

IRC’ing the night away

| | Comments (0) | TrackBacks (0)

IRC is a "chat" protocol which is fairly popular with the open source crowd. Most of the time getting an answer over IRC can be quicker and less painful than searching the internet, or posting to a mailing list, newsgroup, or forum.

Because IRC is such a ubiquitous communication channel, it is extremely useful for maintaining contact with others. Often the creator of an open source project will create an IRC channel to facilitate communication with the users of his or her software. I plan on showing you all how to safely create just such a channel.

My example makes a couple of assumptions:

  • IRC client knowledge
  • Connection to the Freenode network

Let's create a new channel for our fictional open source project -- GreatProject.

First, we need to make sure we have a registered nickname I won't go into great detail about this but you need to run a command like this one:

[freenode] /msg nickserv identify supersecretpassword

You should see output like this in your client:

20:59 -NickServ(NickServ@services.)- Password accepted - you are now recognized

To learn more about the NickServ service, and about registering your nickname visit the Freenode FAQ page about setting up your nick

You need to first create your new channel, on Freenode at least this is as easy as joining your channel:

[freenode] /join #greatproject

That command should create the following output:

21:34 -!- friocorte [n=dcarter@dsl027-165-128.atl1.dsl.speakeasy.net] has joined #greatproject 21:34 -!- ServerMode/#greatproject [+ns] by niven.freenode.net 21:34 [Users #greatproject] 21:34 [@friocorte] 21:34 -!- Irssi: #greatproject: Total of 1 nicks [1 ops, 0 halfops, 0 voices, 0 normal] 21:34 -!- Channel #greatproject created Fri Sep 28 21:38:21 2007 21:34 -!- Irssi: Join to #greatproject was synced in 0 secs

Now you should register your channel:

[freenode] /msg chanserv register #greatproject supersecretpasswordtwo

Here's what you should see:

21:57 -ChanServ(ChanServ@services.)- The channel [#greatproject] is now registered under your nickname. 21:57 -ChanServ(ChanServ@services.)- Your channel password is [supersecretpasswordtwo]. Please remember it for later use. 21:57 -ChanServ(ChanServ@services.)- Channel guidelines can be found on the freenode website 21:57 -ChanServ(ChanServ@services.)- (http://freenode.net/channel_guidelines.shtml). 21:57 -ChanServ(ChanServ@services.)- freenode is a service of Peer-Directed Projects Center, an IRS 501(c)(3) 21:57 -ChanServ(ChanServ@services.)- (tax-exempt) charitable and educational organization.

Don't forget your password, you'll need it to make any future sessions.

Tomorrow, we'll show you how to control your channel and the users who will connect to it. So stay tuned.

Asterisk Queues REDUX

| | Comments (0) | TrackBacks (0)

I love tinkering with stuff. But sometimes it takes me too long to get something to work like it want it to. We bit off a little more than we could chew with this current Asterisk dialplan. I've solved most of these problems as best I know how. Here are the requirements (as far as I understand them):

  • Calls from queues should be distributed as fairly as possible
  • Calls from queues should cascade out to as many avalible agents as possible
  • Agents should be able to log into their assigned queues from any phone
  • Agents should be able to log into, and manage calls from multiple queues
  • Agent phones should only receive one call at a time from any of the queues they have logged into
  • Agent phones should be reachable via direct dialing, even when handling a call from a queue

Let's look at each of these items one at a time:

Calls from queues should be distributed as fairly as possible

The goal here is to give every agent at least a chance to answer a call if the agent before him/her doesn't. You might think that the answer is to do round-robin queueing, however that is incorrect, as the first agent will always get the first call after a lull of calling. We chose to use rrmemory queueing which is round robin with memory. Each time a call starts going around round robin, the system remembers where it last sent a call, and picks up from there the next time around.

Calls from queues should cascade out to as many avalible agents as possible

Originally in Asterisk the queues wouldn't send a call to another available agent until the first call had been picked up. To make a queue act more like a "queue should work" enable the option autofill=yes.

Here is a sample of my queues.conf file:

[general] persistentmembers=yes ; store agent login in astdb autofill=yes ; automaticlly dial as many agents as there are phone calls memberdelay=0 ; how long to wait until the agent is connected to the caller announce-frequency=90 ; how often do we announce "you are # in line" periodic-announce-frequency=30 ; how often do we announce "your call is really important to us" announce-holdtime=yes ; announce hold time to caller announce-round-seconds=10 ; do we round seconds? joinempty=yes ; allow people into a queue when there are no agents? reportholdtime=no ; tell agent how long the caller was holding ringinuse=no ; do we ring a extension which is 'in use'? retry=0 ; how long to wait until we re-ring the queue with the call (after a deny or busy etc?) timeout=20 ; how long to ring the agent before trying someone else wrapuptime=5 ; how long to wait after the call is completed (allows agent to clean up ticket, etc) [pineapple] strategy=rrmemory [1] strategy=rrmemory reportholdtime=yes [2] strategy=rrmemory reportholdtime=yes [3] strategy=rrmemory timeout=20 retry=15 joinempty=no

Agents should be able to log into their assigned queues from any phone

To accomplish the truly mobile workforce we want, our agents need to be able to accept calls from various queues wherever they may be. We've solved this problem by using strictly dynamic queue agents. This means we don't pre-define agents in agents.conf. An example of the function to log agents in and out of a queue will be provided below.

Agents should be able to log into, and manage calls from multiple queues

We have need for persons sitting at the phones to be able to handle incoming calls from multiple queues. They need to be able to selectively log into and out of multiple queues easily.

Here is the sample of the queue login logout function

[macro-queueloginout] ; first argument is the queue to be added to, second(not yet implemented) is penality exten => s,1,Answer() ; Pick up the phone exten => s,n,Set(MYNUMB=${CUT(CHANNEL,-,1)}) ; clean up the channel name (remove unique id) exten => s,n,Set(MYNUMBCLEAN=${CUT(MYNUMB,/,2)}) ; clean up the channel name (remove technology) exten => s,n,Verbose(99|mynumb is ${MYNUMB} mynumbclean is ${MYNUMBCLEAN}) ; debugging output to see if VARS got set correctly exten => s,n,Set(OUR_QM_LIST=${QUEUE_MEMBER_LIST(${ARG1})}) ; assign member list to variable so it doesn't change exten => s,n,Set(CHANNEL_TO_MATCH=${EVAL(Local/${MYNUMBCLEAN}@queueagents/n)}) ; set what we're matching against exten => s,n,Set(X=1) ; initialize counter ; begin while loop exten => s,n,While($[${EXISTS(${CUT(OUR_QM_LIST,\,,${X})})}]) ; while we still have a value (not-null), loop exten => s,n,Set(OUR_ITTR=${CUT(OUR_QM_LIST,\,,${X})}) ; set our itterator to check exten => s,n,Noop(prematch) ; debugging can probally be removed exten => s,n,Set(MATCHED=${IF($["${OUR_ITTR}" = "${CHANNEL_TO_MATCH}"]?1:0)}) ; match against the channel exten => s,n,Noop(postmatch) ; debugging can probally be removed exten => s,n,Exec(${IF($[${MATCHED}]?ExitWhile():NoOp())}) ; exit while loop on match exten => s,n,Set(X=$[${X} + 1]) ; increase the iterator exten => s,n,EndWhile() ; end while loop exten => s,n,GotoIf($[${MATCHED}]?100,1:400,1) ; branch on match, 100 means yes 400 means no exten => 100,1,noop(yup) ; agent is already logged in, log em out ; TODO add confirmation "do you really want to logout?" exten => 100,n,RemoveQueueMember(${ARG1},Local/${MYNUMBCLEAN}@queueagents/n) ; remove Local/*@queueagents instead of default exten => 100,n,playback(agent-loggedoff) ; tell them the agaent logged off exten => 100,n,Hangup exten => 400,1,noop(nope) ; agent is not logged in, log em in exten => 400,n,AddQueueMember(${ARG1},Local/${MYNUMBCLEAN}@queueagents/n,0) ; add Local/*@queueagents instead of default ; catch if queuemember breaks exten => 400,n,Execif($[ ${AQMSTATUS} = ADDED ],Playback,agent-loginok) ; let the agent know they have sucessfully logged in exten => 400,n,Execif($[ ${AQMSTATUS} = NOSUCHQUEUE ],Playback,try-again) ; if queue doesn't exist tell em to try again. exten => 400,n,Hangup

Agent phones should only receive one call at a time from any queue

This requirement combined with the next one, became the biggest hurdle to overcome. If we restricted the number of calls via limits in sip.conf then the requirement below was not met, and if we didn't use limits in queues.conf then we had to disable any and all call-waiting on the phones(completely un-wanted side effect).

Agent phones should be reachable via direct dialing, even when handling a call from a queue

We ended up using the following tactic to satisify these two requirements. First, we didn't just add the channel that dialed the login macro, we added a related macro in the queueagents context. This is done by the following line in the macro posted above:

exten => 400,n,AddQueueMember(${ARG1},Local/${MYNUMBCLEAN}@queueagents/n,0) ; add Local/*@queueagents instead of default
We used the following logic in the queueagents context, which keeps track of which members are currently being called, and returns busy() if needed.
[queueagents] exten => _XXXX,1,noop(${EXTEN}) ; queue agent context, extension is agent to call exten => _XXXX,n,Set(GROUP(${EXTEN}@queueagents)=1) ; set the group to @queueagents exten => _XXXX,n,Set(MYCOUNT=${GROUP_COUNT(${EXTEN}@queueagents)}) ; retrieve the number of active calls exten => _XXXX,n,GotoIf($[${MYCOUNT} > 0]?busy) ; if the number of calls is greater than zero, goto the busy priority exten => _XXXX,n(avail),NoOp(avail) ; Availble priority, can be used to override call limits eg( goto queueagents,${EXTEN},avail ) exten => _XXXX,n,Set(OUTBOUND_GROUP=${EXTEN}@queueagents) ; Setup the magic OUTBOUND_GROUP varible, (increments the count next time someone attempts to call exten => _XXXX,n,Dial(SIP/${EXTEN}) ; if we got to here, then it's clear to call, dial away. TODO: Make the technoligy dynamic to allow IAX agents etc exten => _XXXX,n,Goto(done) ; skip over the busy priority exten => _XXXX,n(busy),NoOp(busy) ; busy priority exten => _XXXX,n,Busy() ; send busy to the queue exten => _XXXX,n(done),NoOp(done) ; done priority exten => _XXXX,n,Hangup() ; all done

One last thing we did was to override the caller ID so the agent could answer the phone according to the type of call. We did this just before calling the Queue() application in the dialplan.

exten => _54XX,1,Answer exten => _54XX,1,Wait(2) exten => _54XX,n,Playback(you-entered) exten => _54XX,n,SayAlpha(q) exten => _54XX,n,SayDigits(${EXTEN:3:1}) exten => _54XX,n,Set(CALLERID(name)=Queue -- ${EXTEN:3:1}) exten => _54XX,n,Queue(${EXTEN:3:1}) exten => _54XX,n,Hangup

Thanks and acknolegements

Getting this thing working wouldn't have been possible without Jared Smith's help, both direct help via IRC or indirect help via his book. If you're using Asterisk and don't have this book, you are working too hard. I would also like to thank those from the Utah Asterisk User's Group who chimed in the IRC channel. Now go buy Jared's book to help me feel less guilty about bothering him every day for the past three weeks.

Asterisk Queues

| | Comments (0) | TrackBacks (0)

I've been busy lately working on a rather big Asterisk installation.

One of the bigger problems we've wanted to solve was our queue management.

Here's the beginnings of a queue log in/out macro I've been fiddling with.

oh, and a super-big thanks goes to Jared Smith, for the basis of what I've done here.

; macros to do login and out of queues [macro-queueloginout] ; first argument is the queue to be added to, second(not yet implemented) is penality exten => s,1,Answer exten => s,n,Set(MYNUMB=${CUT(CHANNEL,-,1)}) exten => s,n,Set(MYNUMBCLEAN=${CUT(MYNUMB,/,2)}) exten => s,n,Set(OUR_QM_LIST=${QUEUE_MEMBER_LIST(${ARG1})}) ; assign member list to variable so it doesn't change exten => s,n,Set(CHANNEL_TO_MATCH=${CUT(CHANNEL,-,1)}) ; get rid of the unique identifier on the end exten => s,n,Set(X=1) ; initialize counter exten => s,n,While($[${EXISTS(${CUT(OUR_QM_LIST,\,,${X})})}]) ; while we still have a value (not-null), loop exten => s,n,Set(MATCHED=${IF($["${CUT(OUR_QM_LIST,\,,${X})"} = "${CHANNEL_TO_MATCH}"]?1:0)}) ; match against the channel exten => s,n,Exec(${IF($[${MATCHED}]?ExitWhile():NoOp())}) ; exit while on match exten => s,n,Set(X=$[${X} + 1]) ; increase the iterator exten => s,n,EndWhile() ; End of the loop exten => s,n,GotoIf($[${MATCHED}]?100,1:400,1) ;branch on match, 100 means yes 200 means no exten => 100,1,noop(yup) ; agent is already logged in, log em out exten => 100,n,RemoveQueueMember(${ARG1},Local/${MYNUMBCLEAN}@queueagents/n) exten => 100,n,playback(agent-loggedoff) exten => 100,n,Hangup exten => 400,1,noop(nope) ; agent is not logged in, log em in exten => 400,n,AddQueueMember(${ARG1},Local/${MYNUMBCLEAN}@queueagents/n,0) ; catch if queuemember breaks exten => 400,n,Execif($[ ${AQMSTATUS} = ADDED ],Playback,agent-loginok) exten => 400,n,Execif($[ ${AQMSTATUS} = NOSUCHQUEUE ],Playback,try-again) exten => 400,n,Hangup

It is still a work in progress, I'm hoping to get a penality overload built into the macro in the near future.

Oh, yeah! I almost forgot to show you how to use the macro in your dialplan:

exten => _77XX,1,Macro(queueloginout,${EXTEN})

This extension, anything in the 7700 range, will log the currently calling phone into the queue specified, numbered by the extension dialed. E.g. dial 7703 will log you into or out of queue 7703.

UPDATE 2007-05-10

I was fiddling with this, and realzed that only one agent could log in at a time.

Thanks again to Jared for discovering that adding four little quote marks makes it work correctly.

post above edited to show the new quotes.