New Adhearsion Feature: Sexy Rails integration 3

Posted by Jay Phillips Mon, 25 Feb 2008 08:21:00 GMT

This feature has been in trunk for a while so it’s time to bring it into the limelight.

Let’s say you’ve a really fancy Ruby on Rails web application with which you wish to integrate your new Adhearsion app. Though you may only need five or so of the thirty models that exist within the app, they’re inter-related somehow with has_many :through, belongs_to and a dozen other SQL fragments sprinkled about. That’s no good—looks like it’s all or nothing. Oh, and you’ve eight Rails plugins installed, of which five heavily modify ActiveRecord’s internals for your obscure purposes. That’s no good, either. Looks like it all of Rails or nothing.

You can now do this “all of Rails” integration extremely easily in Adhearsion. When you create a new Adhearsion app with trunk, you’ll see the following option in config/startup.rb:

config.enable_rails :path =>/path/to/your/rails/project”, :env => :development

And voila! Just uncomment this line and point it to the appropriate path. Adhearsion will do the rest.

When the Rails application loads, Adhearsion doesn’t bother initializing any of the web servers that may slow it down. The only real penalty is the negligible consumption of memory it brings with it.

Still more features to blog about! Stay tuned…

New Adhearsion Feature: Dialplan Menus 5

Posted by Jay Phillips Tue, 12 Feb 2008 04:23:00 GMT

Those who watch the Adhearsion trunk commits probably noticed a new feature I snuck in recently: the menu() dialplan command. Now that I’ve had a chance to actually use the feature myself, it’s time I cover it in more detail here.

For the record, I’m totally excited about it. I’ve wished for something like this for over a year and only recently did I discover a way to get around the one technical limitation to implement it.

The problem

The menu() command solves the problem of building enormous input-fetching state machines in Ruby without first-class message passing facilities or an external DSL. After completely scrapping the feature several times and starting over, I eventually settled on my design of a state machine using a second-class message passing pattern. I’ll be writing about this pattern soon here.

Meet menu()

For now, here’s an example of menu():

from_pstn {
  menu 'welcome', 'for-spanish-press-8', 'main-ivr',
       :timeout => 8.seconds, :tries => 3 do |link|
    link.shipment_status  1
    link.ordering         2
    link.representative   4
    link.spanish          8
    link.employee         900..999

    link.on_invalid { play 'invalid' }

    link.on_premature_timeout do |str|
      play 'sorry'
    end

    link.on_failure do
      play 'goodbye'
      hangup
    end
  end
}

shipment_status {
  # Fetch a tracking number and pass it to a web service.
}

ordering {
  # Enter another menu that lets them enter credit card
  # information and place their order over the phone.
}

representative {
  # Place the caller into a queue
}

spanish {
  # Special options for the spanish menu.
}

employee {
  dial "SIP/#{extension}" # Overly simplistic
}

If you haven’t, take a minute to read the dialplan above before reading on.

The main detail to note is the declarations within the menu() command’s block. Each line seems to refer to a link object executing a seemingly arbitrary method with an argument that’s either a number or a Range of numbers. The link object collects these arbitrary method invocations and assembles a set of rules. The seemingly arbitrary method name is the name of the context to which the menu should jump in case its argument (the pattern) is found to be a match.

With these context names and patterns defined, the menu() command plays in sequence the sound files you supply as arguments, stopping abruptly if the user enters a digit. If no digits were pressed when the files finish playing, it waits :timeout seconds. If no digits are pressed after the timeout, it executes the on_premature_timeout hook you define (if any) and then tries again a maximum of :tries times. If digits are pressed that result in no possible match, it executes the on_invalid hook. When/if all tries are exhausted with no positive match, it executes the on_failure hook after the other hook (e.g. on_invalid, then on_failure).

When the menu() state machine runs through the defined rules, it must distinguish between exact and potential matches. It’s important to understand the differences between these and how they affect the overall outcome:

exact matches potential matches result
0 0 Fail and start over
1 0 Match found!
0 1 Get another digit
0 >1 Get another digit
>1 0 Go with the first exact match
1 >0 Get another digit. If timeout, use exact match
>1 >0 Get another digit. If timeout, use first exact match

Database integration

To do database integration, I recommend programatically executing methods on the link object within the block. For example:

menu do |link|
  for employee in Employee.find(:all)
    link.internal employee.extension
  end
end

or this more efficient and Rubyish way

menu do |link|
  link.internal *Employee.find(:all).map(&:extension)
end

If this second example seems like too much Ruby magic, let me explain — Employee.find(:all) effectively does a “SELECT * FROM employees” on the database with ActiveRecord, returning (what you’d think is) an Array. The map(&:extension) is fanciness that means “replace every instance in this Array with the result of calling extension on that object”. Now we have an Array of every extension in the database. The splat operator (*) before the argument changes the argument from being one argument (an Array) into a sequence of n arguments, where n is the number of items in the Array it’s “splatting”. Lastly, these arguments are passed to the internal method, the name of a context which will handle dialing this user if one of the supplied patterns matches.

Handling a successful pattern match

Which brings me to another important note. Let’s say that the user’s input successfully matched one of the patterns returned by that Employe.find... magic. When it jumps to the internal context, that context can access the variable entered through the extension variable. This was a tricky design decision that I think, overall, works great. It makes the menu() command feel much more first-class in the Adhearsion dialplan grammar and decouples the receiving context from the menu that caused the jump. After all, the context doesn’t necessary need to be the endpoint from a menu; it can be its own entry point, making menu() effectively a pipeline of re-creating the call.

I encourage you to give this command a try and let me know what you think! Feel free to post on the mailing list or here on my blog.

Enjoy, folks!

The Year of Adhearsion 6

Posted by Jay Phillips Thu, 27 Dec 2007 05:30:00 GMT

I get dizzy when I think of the flash flood of memories 2007 has been. I remember what I was doing precisely one year ago as if it were yesterday:

Sitting in my cozy dormitory bedroom, the first signs of relief set in as the stretch lasting almost two months was coming to an end—I was tying up the loose ends of my first publicly released version of Adhearsion. The start of the stretch was marked by my irreverent albeit desperate sneaking into Astricon 2006, the big Asterisk conference held ironically just six miles away in downtown Dallas at which security was surprisingly lax. It was there that I first demoed an alpha of Adhearsion to respected players in the telecom industry. My demo’s reception motivated me to pursue Adhearsion further, potentially toward something big. Through connections established there, I was invited to the headquarters of Asterisk’s corporation Digium twice, wrote an article for Linux Journal magazine, and got my first notable Adhearsion speaking opportunity at Emerging Telephony 2007. That was the tipping point.

Since those days I’ve spoken at eleven more conferences and tech meetups, collected hundreds of business cards, written an Adhearsion chapter for O’Reilly’s Asterisk book, and visited three other countries and fifteen states on Adhearsion-related business. To afford the absurd amount of travel, I took up an interesting style of living I later labelled peer-to-peer living: I had no fixed residence and considered myself, basically, homeless. Throughout my travels I managed to develop a support network of individuals with couches to spare for a few days or a few weeks. Needless to say, this all came as a shock to this boy from Texas who had never been out of the South.

This fruitful year is now over, the name Adhearsion is more widely known and, as of last week, I live in a fantastic part of beautiful San Francisco. After twelve months of testing myself and countless days of personal reflection, I’ve confidently decided that Adhearsion is my career now.

Big ’08 holds a lot. In addition to continued development, I want to bring in sub-contractors to assist on increasingly substantial consulting projects and encourage others to start their own independent Adhearsion consulting practice. If you’re a Ruby developer either with VoIP experience or a genuine, keen desire to gain VoIP experience, talk to me. My email address is in the right column of this blog. If you’re a company needing a better phone system or a startup with some telephony component not yet developed, talk to me too and let’s see if using Adhearsion makes sense.

I’ll continue promoting Adhearsion in ways other than speaking at a dozen conferences. Think screencasts, video podcasts, writing, and a revamped website. Development will continue regardless of whether I have work. My first order of business is to get the version 0.8.0 gem out the door. For those that don’t want to wait, you can play with 0.8.0 in Adhearsion’s trunk.

Happy new year folks! Let’s make 2008 the year the telecom industry really changed.

The Lack of Emerging Telephony 4

Posted by Jay Phillips Sat, 13 Oct 2007 19:43:00 GMT

The telephony industry sickens me. I make it a point to follow things closely. I sift through the nauseatingly boring Del.icio.us VoIP feeds, catching the occasional library I hadn’t seen before that mildly captures my interest. I hear that SuperBigComm has bought TinySmallVox every week or so. I subscribe to the feeds of the VoIP’s biggest bloggers (of which there are surprisingly few) and usually read their posts last, procrastinating the tedium. I don’t unsubscribe and keep the faith because I want to believe this industry is going somewhere.

But last night my feeds agreed with my doubts. Resounding through the VoIP blogosphere, O’Reilly announced they have cancelled their Emerging Telephony conference and blog. To help paint the picture, Emerging Telephony was widely considered to be one of the actually fun, innovative conferences every year in this space.

Therein lies the problem. Too little fun and innovation exists in this industry to make a full conference out of it.

Remember the last episode of Star Trek: The Next Generation where the omnipotent Q places all of humanity on trial for being a savage, inferior species? Q asserts that the years since the first time he placed humanity on trial has been squandered with virtually no progress toward enlightenment. I’m convinced Q was so pissed off because of this ridiculous blemish in our history. We are a savage, uncivilized race apparently.

This is a frustration I’ve had since I created Adhearsion. The framework’s name reflects my attempt to unify this godforsaken wilderness. I’m herding cats and fighting the good fight simultaneously.

But I’m not giving up yet.

There are many wonderful things brewing under the covers of the new version of Adhearsion. It’s a maverick, opinionated approach but it may just work. The effect could be truly disruptive:

  • A significantly next-generation approach reaches hackers who can finally develop actual open-source VoIP applications.
  • An open-source ecosystem forms.
  • More people become professional VoIP developers.
  • Additional global expertise increases the number of open-source VoIP applications.
  • The ability to host the applications becomes predictable and inexpensive through standardization.
  • Startups form around new applications.
  • A few startups succeed and contribute back.
  • Years of contributions improves software quality and lowers barrier to entry.
  • Disruptively innovative companies catch big telecom companies with their pants down and chip away at their market share.

The fight will be a long and difficult one, though the next baby step is to get Adhearsion v0.8.0 out the door. Near the end of the this month I’ll outline the changes in the new version of Adhearsion which should see a release by RubyConf on November 4th, 2007!

Full Video Recording of my Ruby Hoedown Presentation 6

Posted by Jay Phillips Tue, 21 Aug 2007 13:23:00 GMT

On August 10th I gave a presentation about Adhearsion at the Ruby Hoedown conference. Despite only two hours of sleep the night before, I think it came out quite well.

The ConFreaks guys were there and recorded my presentation. It’s completely available online on their website here. It can also be downloaded in AVI format at 640×240 or 960×360.

Here are a few snapshots from my talk:




Adhearsion v0.8.0 and Beyond

Posted by Jay Phillips Mon, 16 Jul 2007 20:22:00 GMT

It was about one year ago that the Adhearsion name came to be, along with an invigorating second wind to develop it after writing Rails apps for several months and seeing real Ruby development. The ease and sense I saw Ruby make in the web development scene was an enormous inspiration to build Adhearsion into what it is today and what it will soon become.

It's this near future that excites me the most. For the past few months I've been intensively working on a rewrite of the Adhearsion core and it's showing great promise. Since I've never formally announced my intentions, here is what the community can expect from Adhearsion v0.8.0:

  • Sustained quality. An enormous problem with Adhearsion 0.7.x has been avoiding regression when changes are made. The codebase today is unfortunately very monolithic and, consequentially, very easy for a change in one area to affect the rest of the framework without my knowing until someone reports it on the mailing list. This time around I am working on 100% RSpec coverage of Adhearsion and using the development principles of Behavior Driven Development. The telecom world expects rock solid dependability and Adhearsion should never be a question mark.
  • First-class community portal. Another big issue in the Adhearsion scene I'm noticing is a weak adhesion (pun intended) of the Adhearsion community. My vision long ago was to facilitate the exchanging of Adhearsion-related source code on the official Adhearsion website. The problem has been in finding time to develop this community portal. Thankfully an opportunity arose to work with Alex Pilafian of Sikanrong.com on the site. In just the one month we've been developing it we've made enormous headway. Imagine this: a community-maintained open-source call center application exists online at Adhearsion.com; the "ahn" command allows dead-simple ease of deployment with only "ahn install appname"; suddenly you receive a fully functional call center PBX with AJAX-enabled web frontend, PBX clustering support, Java integration (mentioned below), easily maintainable application code, and all of the other benefits of Adhearsion. Yes, it's pretty exciting, disruptive stuff. I'll write more about this as it nears completion.
  • Steps toward PBX independence. In doing some consulting for Gaboogie, I've been steadily working on FreeSwitch bindings to Adhearsion for them which will ultimately become open-source and standard with Adhearsion. FreeSwitch is still pre-beta at the moment but does tackle scalability very well. Unlike Asterisk where most of the functionality is already written and must be abstracted, FreeSwitch simply opens APIs for the implementor to develop his own functionality. This means more work on my end but, ultimately, a more robust and modifiable set of VoIP applications.
  • New Asterisk Manager Interface library. Adhearsion AMI features are presently based on the two-year old RAMI library which exposes an API to read and execute Asterisk events outside of live phone calls. The library definitely shows its age, being a very tangly mess of unintuitive code that I'd expect from the non-Prototype Javascript world but not from the Ruby '07 scene. Dave Troy and I sat down at the Asterisk Developers Conference in Atlanta a few months ago and pounded out an unprecedented new library that vastly improves Asterisk integration.
  • JRuby compliance. At RailsConf 2007, Charles Nutter and Thomas Enebo demonstrated deploying Mephisto on Glassflish in front of our eyes during a three-hour tutorial session. In the lobby immediately after their presentation I was able to replicate their success by deploying a simple "hello world" Rails app. Now with JRuby v1.0.0 stable out in the wild with "complete" 1.8.5 compliance, Adhearsion can be deployed seamlessly with other Java technologies. With Microsoft's efforts in the IronRuby space, a Ruby interpreter written in .NET, Adhearsion's use of the Ruby platform will make integration with that microcosm native, too. Of course, provided Microsoft doesn't fork our language! (J#, anyone?)
  • More on Micromenus. With both the advent of the iPhone and its need for a good SDK, I've been working on the new Micromenus namespace that will render special iPhone-specific interfaces. With this complete, database-driven Micromenus applications can be busted out in minutes, complete with Asterisk integration out of the box. I don't want to spill these beans quite yet so stay tuned. :)

There are a few other things I'll leave in as surprises for the 0.8.0 release but this list should whet your appetite.

Beyond Adhearsion v0.8.0 there are many things on the roadmap, some of which will be axed and some of which will remain. Perhaps the biggest feature in my mind for version 1.0.0 stable will be a real abstraction of the PBX, letting the implementor not worry about any of the inconsistencies of the underlying framework. Adhearsion v0.9.x will be the first step toward the PBX independence and, when sufficient and stable, the 1.0 release will be triggered.

In the meantime, I'd love for others' help in this exciting ramping up phase! Let me know if you've like to lend a hand!

Adhearsion IRC Channel

Posted by Jay Phillips Mon, 16 Jul 2007 20:14:00 GMT

Need help getting started with Adhearsion? Having issues with your Adhearsion deployment? Want to become an Adhearsion developer and need pointers in the right direction?

Join #adhearsion on irc.freenode.net. I'll be hanging out there whenever I'm on an internet-accessible machine.

First Adhearsion Job Posting 33

Posted by Jay Phillips Fri, 22 Jun 2007 08:19:00 GMT

The first of its kind (to my knowledge), EngineYard posted a job search for someone to develop their in-office PBX, requiring Adhearsion skills. EngineYard’s definitely on the right track—especially since so much of their own infrastructure is written with Ruby and things such as in-office PBXs can be done extremely effectively with Adhearsion. Hopefully other companies with follow their lead and support pioneers in this new Adhearsion frontier.

Though I make my business in Adhearsion consulting, I’m totally open to developers jumping on these kind of postings. I couldn’t be happier to have Adhearsion perpetuate its own economy — even if that means people beat me at price occasionally. :)

Extended Adhearsion Excerpt from the New Asterisk Book 1

Posted by Jay Phillips Wed, 20 Jun 2007 06:20:00 GMT

As alluded to in my last post, today O’Reilly’s Emerging Telephony blog published an extended excerpt I wrote about Adhearsion for the new Asterisk book. Content-wise it’s on par with my Linux Journal Magazine article, though quite a bit more current.

If you’ve not seen much of Adhearsion, this is a great starting resource! If you’ve friends or colleagues who you think may find Adhearsion useful, send along the URL!

Adhearsion in Asterisk The Future of Telephony 2nd Edition

Posted by Jay Phillips Fri, 01 Jun 2007 04:30:00 GMT

Having many, many fond memories of thumping the O'Reilly Asterisk bible since I began Asterisk development in Houston, I never imagined I'd write a section for it!

I'm pleased to announce that the second edition of the book, scheduled to hit the shelves later this year, will have a section about installing and using Adhearsion. This will be an enormous booster to the community adoption of Adhearsion -- I can't think of any better publication to feature the framework!

O'Reilly's Emerging Telephony blog will also soon feature an "extended excerpt" from the book about Adhearsion. It is much longer than the section in the book, much more in-depth, and free! For newcomers, there is also the Linux Journal Magazine publication from last March.

Many thanks to O'Reilly for these fantastic opportunities!

Adhearsion Roadshow Tour Dates

Posted by Jay Phillips Thu, 31 May 2007 21:21:00 GMT

Perhaps "roadshow" isn't the right term but I am doing quite a bit of Adhearsion and VoIP promotion. Below is the current list. As I land more, I'll expand it:

Past speaking events:

  • Emerging Telephony, San Francisco, Feb 27th
  • Gotham Ruby Conference, NYC, April 21st
  • Boulder/Denver.rb, May 15th
  • Asterisk Developers Conference, Atlanta, May 22nd

Upcoming speaking events:

  • Cluecon, Chicago, June 26th
  • PDX.rb, Portland, July 3rd
  • Ruby Hoedown, Raleigh, Aug. 10th
  • Lone Star Ruby Conference, Austin, Sept. 8th
  • Astricon, Phoenix, Sept. 24th

Unconfirmed Events:

  • FOSCON, Portland, July 26th

If you are a member of a Ruby brigade or Asterisk users group and would like me to present, shoot me an email. My contact info is available on the Adhearsion contact page.

Adhearsion Just Got Way Fast 1

Posted by Jay Phillips Thu, 15 Feb 2007 01:27:35 GMT

Ahh, it’s such a good feeling when you know you just wrote a really awesome feature. Last Saturday, late at night as I was trying to force myself asleep, I had an epiphany that solved the last hurdle I had with implementing a caching system in Adhearsion. The next morning I sat down and busted out a nineteen line method that took me about twenty minutes to write but another ninety minutes to document!

This cache method now lets Adhearsion totally bypass interpreting the dial plan for incoming calls which have already been cached. Does your dial plan make heavy use of your database? Does it use a really “expensive” helper that’s very resource-intensive? Are you pushing hundreds of calls a minute? So what? You can cache now!

For those that want the nitty-gritty, real documentation, see Adhearsion’s RDocs at http://rdocs.adhearsion.com. Scroll down in the top-right pane until you find cache().

I feel if Rembrandt had written this method, its usage still wouldn’t have come out as beautiful.

cache :for => 1.hour do
    play weather_report('Dallas, Texas')
end

... or, how about this hottie:

cache :per => extension do
    user = User.find_by_extension extension
    speak "Calling #{user.name}" 
    dial user, :for => 1.minute
end

... which will store different caches based on the extension the user dialed. Since many IVRs route depending solely on this variable, caching in this case is both smart and fast. The variable per which the caches are stored can be virtually anything.

For the Ruby hackers, here’s the cache method I implemented.

The epiphany I had was to use the return value of Ruby’s handy Kernel#caller method as a Hash key which uniquely identifies the FILE and LINE which invoked cache. Without this, I wouldn’t be able to distinguish between stored caches which occur in the same file or the same context. In the global cache variable ($cache_dir), this Hash of caller()s maps stack traces to another Hash which contains the constraints for the call—that is any use of the :per Hash key argument. This second nested Hash’s constraining keys map to an Array accessed as a queue of Strings which are simply rawr()ed to Asterisk. The time-to-live (specified with the :for Hash key argument) is stored as index 0 of the Array as a Time object. You can see this being stored with the “ttl.from_now” line and accessed with the “queue.first < Time.now” comparison.

For the bolder Adhearsion hackers, I’d like to call to arms anyone who’d be willing to really destroy Adhearsion with stress tests. There’s an open-source SIP stress tester developed by Hewlett Packard called SIPp with which you could pound your Adhearsion-managed Asterisk PBX.

This is the first of many substantial performance improvements coming. I’ve a few other tricks up my sleeves. :)

Adhearsion in Linux Journal Magazine 1

Posted by Jay Phillips Sat, 10 Feb 2007 20:36:51 GMT

Woot! Linux Journal Magazine, the original magazine of the Linux community and a fantastic barometer for exciting new open-source technologies, has published an article I wrote about Adhearsion in their March 2007 issue. These are the guys that had DHH’s smug mug on the cover of their issue devoted almost entirely to Ruby a few months ago.

This issue’s concentration is VoIP, hence Adhearsion’s inclusion. Thus far it’s the best overview of Adhearsion for a newbie so I recommend to everyone reading this now a trip down to your closest Barnes & Nobles to pick up this copy. No really. Go get a copy. Stop reading my blog, grab your keys, and go.

I chose to send Linux Journal my article because I have an enormous respect for them. I’ve been a reader of their issues for many months and with every issue I find something great. Hopefully people can say the same with this issue referring to Adhearsion. :)

Jay’s got pics:

What is Adhearsion?

Posted by Jay Phillips Sat, 10 Feb 2007 20:14:39 GMT

“Adhearsion! Adhearsion! Adhearsion!” has been my mind’s mantra for many months now. Though Adhearsion.com went live Christmas along with the first release, it’s never received due announcement on my blog. Well, here you go folks.

Adhearsion is new twist on collaboration technologies. Its name derives from its VoIP-oriented origins as “adhesion you can hear” because it understands the VoIP picture and ties many VoIP-related (or, rather, collaboration related) technologies together in a comprehensive solution. From Adhearsion.com, these technologies include:

  • Writing call-processing instructions
  • Trading VoIP functionality
  • Integrating with on-phone XML-based microbrowsers
  • Collaborating with technology beyond VoIP
  • Database integration for DB-driven VoIP apps
  • Sophisticated relationships with Asterisk’s internals
  • Opening up your PBX to RPC distributed computing

...to name a few. The end result is an exciting albeit lightweight package that is simply fun to hack with and beautifully simple. I wake up each morning giddy to resume my programming on Adhearsion from the previous night because each day brings some new and exciting possibility. This passion too is now shared — more are joining the project and more are seeing this vision. It’s great how all this is falling in place.

So great in fact my company Codemecca LLC is now the Adhearsion company. It will be the official sponsor of Adhearsion’s development and proliferation while bringing Adhearsion to the small business and enterprise markets through training, consulting, support, and so forth.

Technically, Adhearsion is written in Ruby with a sweet helper architecture. These “helpers” or framework extensions can be written in Ruby or C (more languages coming) and plug right into your app to extend, for example, the dial plan instructions or to introduce instant messaging functionality over Jabber.

In the spirit of “adhearing” things together, functionality brought by helpers can be used for your PBX, by other helpers, or — and this is the key — over Remote Procedure Calls (RPC). Take for example credit card processing. A new company wants to provide a public number into which customers can call and place orders for particular items. Also, because we’re living in the 21st century, they want to have the same credit card processing logic available to their PHP/Rails/Django/J2EE/whatever web apps. Writing the credit card processing logic in Adhearsion makes the functionality available to the PBX, but also to any other program or service needing it within the company. And by the way, writing that actual logic and having it set up like this would require nearly no effort whatsoever.

Stay tuned on this blog for more updates on Adhearsion. I’m hitting a wall with my custom blogging software Gosling and will soon be switching over to Typo. This will make the blog a much nicer place to facilitate my ramblings. :)

My Interview with Mind Petals, the Young Entrepreneur Network 1

Posted by Jay Phillips Sat, 30 Dec 2006 01:45:32 GMT

Poking through my del.icio.us web design feeds one early September morning, I stumbled across one site bookmarked with the description “CHECK OUT THIS GREAT DESIGN!”

Totally falling for Mr. CAPSLOCK’s effectiveness, I obeyed. “MindPetals.com, the young entrepeneur’s network” caught my eye and my eyebrows shot up. Coincidentally, this was just around the time I was forming my company Codemecca, making me a new, young entrepeneur.

I emailed Mind Petals’ owner Dave Askaripour and we’ve been keeping in touch ever since. He’s recently entered the printed newletter market and, for his first issue, he asked to interview me on the great growth of Codemecca since we first met.

The interview’s now on the Mind Petals website. It’s a good read – go check it out and snag his feed!

Older posts: 1 2