<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description>A tumble log by Steve Jabour.</description><title>Allometry</title><generator>Tumblr (3.0; @allometry)</generator><link>http://allometry.com/</link><item><title>The Case for Better Customer Service</title><description>&lt;p&gt;I view software as a service, similar to working the floor at any box retailer. As a software developer, you&amp;#8217;re often put into a position of direct customer interaction and in the case of released or mature software, that interaction most likely involves fixing or adding something.&lt;/p&gt;
&lt;p&gt;Sometimes, customers can be critical. It&amp;#8217;s important to keep in mind where that criticism is coming from and what&amp;#8217;s the end goal. Sometimes, it can be easy to get defensive and that can make a simple situation turn unpleasantly complex.&lt;/p&gt;
&lt;p&gt;Customers are driven by the value they perceive from your product against how much money they spent to get it. They aren&amp;#8217;t typically driven to manipulate situations to gain more from you as a producer or supplier and are usually critical when expectations aren&amp;#8217;t met.&lt;/p&gt;
&lt;p&gt;Starting in January, I made a personal note that 2012 is the year of the customer. It&amp;#8217;s a personal goal that I do a better job at interacting with my customers and treating them how I expected to be treated as a client. Since making this note, I feel I have done a better job at providing a higher level of customer service, but there&amp;#8217;s still room for improvement!&lt;/p&gt;
&lt;p&gt;That being said, I noticed that as I increased my level of service, I began to tolerate underperforming or poor customer service very little.&lt;/p&gt;
&lt;p&gt;One of the lessons that should be noted was one I experienced, as a customer, today at a local car wash. Before leaving the establishment, I noticed a rather large smudge on my seat, in the shape of a footprint. No big deal, I expect that folks have to climb in and out of a vehicle to clean it, but I expect it to be cleaned up.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s a busy day at the car wash and service staff are likely instructed to dry and move onto the next vehicle as quickly as possible. While one of the staff members humored my request, the smudge was only half-cleaned. Before I could get that person back, they were already onto the next car.&lt;/p&gt;
&lt;p&gt;Next step: grab a supervisor or manager working with these teams and have them fulfill my request, since they typically aren&amp;#8217;t held to the same frantic pace. Here&amp;#8217;s how not to handle the situation:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do not tell the customer that your staff has no reason to climb on your seats!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As a customer, my motive is making sure that I spent my dollar well at an establishment who advertises a proven track record. My total time spent from drop-off to pickup was about 15 minutes. I spent roughly $30.00, compounding a $120.00/hour rate. This is an impressive number, just for washing cars!&lt;/p&gt;
&lt;p&gt;Regardless of my assumptions of rates, product and cost, I proceed to tell the manager that I had already asked to have it cleaned, it just wasn&amp;#8217;t done to my liking. Again, do not follow-up with:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We have no reason to climb on your seats!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is where poor customer service is defined. The manager failed to recognize where the customer&amp;#8217;s criticism was aimed. The customer&amp;#8217;s driving motivation is to be satisfied, not to pick an argument. Now a simple situation has turned complex, because the customer is getting defensive.&lt;/p&gt;
&lt;p&gt;Regardless of where the smudge came from, how it got there, what company policy is or isn&amp;#8217;t, doesn&amp;#8217;t really matter. In business and in dealing with customers, the structured box in which your products or services fit will not always remain neat and tidy. Sometimes, going outside of that comfort zone and bringing that customer back into your realm requires a bit of calm and care.&lt;/p&gt;
&lt;p&gt;The manager should have realized that the customer is just wanting the seat clean, and doesn&amp;#8217;t care about company policy regulating what staff members should and should do. It doesn&amp;#8217;t help the situation to argue with the customer, which leads me into my next no-no:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do not tell the customer he is being rude and getting in the manager&amp;#8217;s face!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This makes a business relationship personal. Now you&amp;#8217;re stepping into territory that can get you fired, if your company lacks tolerance for this kind of behavior. However, as a customer, I don&amp;#8217;t want to see anyone lose their job, because this kind of behavior can be fixed rather easily: don&amp;#8217;t argue over a simple fix that doesn&amp;#8217;t cost the company anything.&lt;/p&gt;
&lt;p&gt;Customers understand that businesses are in business to do one thing: make money. As a customer, I expect that if I demand extra services, the company will demand extra money. That&amp;#8217;s how business works!&lt;/p&gt;
&lt;p&gt;At this point, the manager and I have parted ways. As a customer, I am fuming and feel greatly disrespected by a business I&amp;#8217;ve been attending for decades. Keep in mind, in service, you represent the business. Your customers don&amp;#8217;t relate to a brand when doing direct business, they relate to you!&lt;/p&gt;
&lt;p&gt;Customers can recognize the value of a product in contrast to the actual providers. I feel this way about this car wash, as their brand and product is solid. I have a personal interest in doing business with this company, therefore speaking with someone in a position of power is very important.&lt;/p&gt;
&lt;p&gt;How do you go about repairing a broken business relationship? &lt;strong&gt;Be honest!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Later that afternoon, I spoke with a regional manager for this car wash. They have many locations and built a reputation from the ground up. They are a thriving local business and employ hundreds of people. I appreciate that and hope one day to be as successful. As a customer, I relayed my experiences onto the manager and explained what happened. Most customers can be gracious in complaints and honestly don&amp;#8217;t find pleasure with anyone losing their job. Customers want to know they can still go back to that location with the promise they&amp;#8217;ll be treated better next time.&lt;/p&gt;
&lt;p&gt;The regional manager confirmed my feelings that this situation could have been handled quickly and easily, avoiding any sort of confrontation. In the process, he restored trust with his company&amp;#8217;s image. Hopefully, the offending manager didn&amp;#8217;t lose his job and is open to repairing a business relationship with his customer. Because, as a customer, I&amp;#8217;ll forgive bad service if it&amp;#8217;s replaced by good service!&lt;/p&gt;
&lt;p&gt;In closing, it&amp;#8217;s important to always remember that businesses are competing to earn your dollar. People need to be firm in their stance that they are paying someone else to provide a service for them. The delivery should be professional and meet expectations. It should be done in a pleasant manner, which invites the customer to return and spend more money. The next time you spend a dollar, realize that if your expectations aren&amp;#8217;t being met, say something. No job is beneath anyone and service providers need to realize there are no favors in transacting with customers; only their expectations.&lt;/p&gt;
&lt;p&gt;The customer does you a favor by spending their money at your establishment. Try acting like it!&lt;/p&gt;</description><link>http://allometry.com/post/22505259333</link><guid>http://allometry.com/post/22505259333</guid><pubDate>Sun, 06 May 2012 02:10:00 -0600</pubDate></item><item><title>I like this music. If you enjoy it too, I recommend a purchase...</title><description>&lt;iframe width="400" height="100" style="position: relative; display: block; width: 400px; height: 100px;" src="http://bandcamp.com/EmbeddedPlayer/v=2/album=2849291287/size=venti/bgcol=FFFFFF/linkcol=4285BB/" allowtransparency="true" frameborder="0"&gt;&lt;/iframe&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;I like this music. If you enjoy it too, I recommend a purchase going to some truly great guys!&lt;/p&gt;</description><link>http://allometry.com/post/13950861625</link><guid>http://allometry.com/post/13950861625</guid><pubDate>Thu, 08 Dec 2011 19:47:53 -0700</pubDate></item><item><title>Flash Builder and ASP.NET, Part 2</title><description>&lt;p&gt;In part 1, I describe the overall project and how each piece of this puzzle is linked. In part 2, I&amp;#8217;ll describe how the ASP.NET back end is constructed and some of the lessons I learned along the way with providing data calls over a WCF service.&lt;/p&gt;
&lt;p&gt;After setting up my database and project, I was able to generate the local objects via .NET 3.5&amp;#8217;s ADO.NET Entity Framework. EF is an ORM similar to LINQ, but not limited to MSSQL as it&amp;#8217;s backing database. In this case, I&amp;#8217;d rather use LINQ to SQL since it&amp;#8217;s easier to use, but Entity Framework is a requirement set by the client.&lt;/p&gt;
&lt;p&gt;When you generate your objects with Entity Framework, it&amp;#8217;s important to make sure that you&amp;#8217;ve setup your relationships beforehand. The best way to do this is in the MSSQL designer, where you can actually drag your relationships between tables. MSSQL will then create the foreign key relationships for you and also ask how it should delete related information if the primary source is deleted first. We call this cascading.&lt;/p&gt;
&lt;p&gt;If you do this before hand, you&amp;#8217;ll save yourself time trying to do it in Entity Framework. It&amp;#8217;s best just to let Entity Framework do what it&amp;#8217;s good at and that&amp;#8217;s generating objects and all the magic to pull your data into some usable C# objects.&lt;/p&gt;
&lt;p&gt;The second piece of this ASP.NET puzzle is the WCF Services. WCF Services are split into two parts: an interface and class. The interface is like any other class interface, where you define the methods available in the class and what they should return. In the case of WCF Services, the interface is where you&amp;#8217;ll define attributes to the class and methods. When you write these classes, Visual Studio will do a lot of the leg work for you, if you just select the WCF Service class template from the new item selector.&lt;/p&gt;
&lt;p&gt;The WCF Service interface and class are the business layer for the whole MVC. This is where, if you need to modify the data before it comes in or goes out, you&amp;#8217;d do that kind of work.&lt;/p&gt;
&lt;p&gt;In the CRUD paradigm, this is what the R part would look like in the interface:&lt;/p&gt;
&lt;p&gt;[ServiceContract]&lt;br/&gt;public interface IUsers&lt;br/&gt;{&lt;br/&gt;   [OperationsContract]&lt;br/&gt;   List&amp;lt;User&amp;gt; retrieve();&lt;br/&gt;}&lt;/p&gt;
&lt;p&gt;and the class:&lt;/p&gt;
&lt;p&gt;public class Users&amp;#160;: IUsers&lt;br/&gt;{   &lt;br/&gt;   MyEntityFramework db = new MyEntityFramework();&lt;br/&gt;   public List&amp;lt;User&amp;gt; retrieve()&lt;br/&gt;   {&lt;br/&gt;       return db.Users.toList();&lt;br/&gt;   }&lt;br/&gt;}&lt;/p&gt;
&lt;p&gt;Pretty easy.&lt;/p&gt;
&lt;p&gt;What all this does is tell ASP.NET how it should handle calls back and fourth and what it is responsible for. It also will tell any other language how to consume data and how it should talk to ASP.NET when transacting information. &lt;/p&gt;
&lt;p&gt;When you generate and write your WCF Services, Visual Studio goes ahead and handles some of the definitions needing to be made in the web.config file.&lt;/p&gt;
&lt;p&gt;The latest and greatest of .NET services consume data over SOAP 1.2, but in the case of Flex, it will only do 1.1. This is where you have to tell the web.config file how to handle that kind of call.&lt;/p&gt;
&lt;p&gt;This is what a service call looks like in the web.config:&lt;/p&gt;
&lt;p&gt;&amp;lt;service behaviorConfiguration=&amp;#8221;Flex_Backend.Services.UsersBehavior&amp;#8221; name=&amp;#8221;Flex_Backend.Services.Users&amp;#8221;&amp;gt;&lt;br/&gt;   &amp;lt;endpoint address=&amp;#8221;&amp;#8221; binding=&amp;#8221;wsHttpBinding&amp;#8221; contract=&amp;#8221;Flex_Backend.Services.IUsers&amp;#8221;&amp;gt;&lt;br/&gt;      &amp;lt;identity&amp;gt;&lt;br/&gt;         &amp;lt;dns value=&amp;#8221;localhost&amp;#8221; /&amp;gt;&lt;br/&gt;      &amp;lt;/identity&amp;gt;&lt;br/&gt;   &amp;lt;/endpoint&amp;gt;&lt;br/&gt;   &amp;lt;endpoint address=&amp;#8221;mex&amp;#8221; binding=&amp;#8221;mexHttpBinding&amp;#8221; contract=&amp;#8221;IMetadataExchange&amp;#8221; /&amp;gt;&lt;br/&gt;&amp;lt;/service&amp;gt;&lt;/p&gt;
&lt;p&gt;It should look like this, provided you want to have both 1.2 and 1.1. calls available:&lt;/p&gt;
&lt;p&gt;&amp;lt;service behaviorConfiguration=&amp;#8221;Flex_Backend.Services.UsersBehavior&amp;#8221; name=&amp;#8221;Flex_Backend.Services.Users&amp;#8221;&amp;gt;&lt;br/&gt;   &amp;lt;endpoint address=&amp;#8221;soap12&amp;#8221; binding=&amp;#8221;wsHttpBinding&amp;#8221; contract=&amp;#8221;Flex_Backend.Services.IUsers&amp;#8221;&amp;gt;&lt;br/&gt;      &amp;lt;identity&amp;gt;&lt;br/&gt;         &amp;lt;dns value=&amp;#8221;localhost&amp;#8221; /&amp;gt;&lt;br/&gt;      &amp;lt;/identity&amp;gt;&lt;br/&gt;   &amp;lt;/endpoint&amp;gt;&lt;br/&gt;   &amp;lt;endpoint address=&amp;#8221;soap11&amp;#8221; binding=&amp;#8221;basicHttpBinding&amp;#8221; contract=&amp;#8221;Flex_Backend.Services.IUsers&amp;#8221;&amp;gt;&lt;br/&gt;      &amp;lt;identity&amp;gt;&lt;br/&gt;         &amp;lt;dns value=&amp;#8221;localhost&amp;#8221; /&amp;gt;&lt;br/&gt;      &amp;lt;/identity&amp;gt;&lt;br/&gt;   &amp;lt;/endpoint&amp;gt;&lt;br/&gt;   &amp;lt;endpoint address=&amp;#8221;mex&amp;#8221; binding=&amp;#8221;mexHttpBinding&amp;#8221; contract=&amp;#8221;IMetadataExchange&amp;#8221; /&amp;gt;&lt;br/&gt;&amp;lt;/service&amp;gt;&lt;/p&gt;
&lt;p&gt;The major differences here is the addition of another endpoint, plus the definition of soap12 and soap11 in the address attributes. Without these additions, Flex will not consume your WSDL.&lt;/p&gt;
&lt;p&gt;Once you&amp;#8217;re WCF Services are written, you&amp;#8217;re ready to test. When you visit your .svc page in a browser, you should be given a link with an ending&amp;#160;?WSDL in the query string. This is what any application will need, if it intends to consume data via WCF.&lt;/p&gt;
&lt;p&gt;Now, with everything in place, your Flex app is ready to start consuming data and that&amp;#8217;s coming up in the next part.&lt;/p&gt;</description><link>http://allometry.com/post/13931224254</link><guid>http://allometry.com/post/13931224254</guid><pubDate>Thu, 08 Dec 2011 13:05:06 -0700</pubDate><category>ASP.NET</category><category>Flex</category><category>WCF Services</category><category>MSSQL</category></item><item><title>Flash Builder and ASP.NET, Part 1</title><description>&lt;p&gt;Its been about a six month drought of no work and I&amp;#8217;ve been trying to keep myself busy by writing in house applications to manage inventory and project information.&lt;/p&gt;
&lt;p&gt;I had a small project come across my plate that is golden for guys like me that like to try and figure out how to make stuff work.&lt;/p&gt;
&lt;p&gt;In this scenario, I needed to accomplish a few things:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Write an ASP.NET web app to supply information via a service using .NET 3.5, ADO.NET Entity Framework and a MSSQL database.&lt;/li&gt;
&lt;li&gt;Write an Adobe Air application to consume those services&lt;/li&gt;
&lt;li&gt;The data model to be diagrammed is nothing more than a two table setup with a 1:n relation.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;That&amp;#8217;s a pretty broad approach to a project, especially since it&amp;#8217;s a proof of concept demonstration that will act as a template, if successful.&lt;/p&gt;
&lt;p&gt;In part 1, I&amp;#8217;ll describe the setup I used to create this demonstration. In subsequent parts, I&amp;#8217;ll dive into specifics on the .NET platform and on the Flex platform.&lt;/p&gt;
&lt;p&gt;The setup is simple: Visual Studio 2010, MSSQL 2008 Express, .NET 3.5.&lt;/p&gt;
&lt;p&gt;We were limited to .NET 3.5, since the organization we&amp;#8217;re building this application for hasn&amp;#8217;t rolled out .NET 4 on any of its desktops or servers. This is pretty typical in my line of work and I&amp;#8217;ve learned to let the frustration go.&lt;/p&gt;
&lt;p&gt;The database is simple: a users table and an items table. A user has many items. A user is an email address and a name, and an item is a key and value.&lt;/p&gt;
&lt;p&gt;The entity framework ORM in .NET 3.5 isn&amp;#8217;t as mature as the version in 4 and it&amp;#8217;s a bit of a pain in the ass at times. However, you can use LINQ with it and that&amp;#8217;s a huge plus.&lt;/p&gt;
&lt;p&gt;When you connect your project to your database, EF can go to work and generate it&amp;#8217;s objects based on your table. From there, you can name the connection string and tell EF what namespace its objects will use. At this point, you&amp;#8217;re pretty much ready to consume data via ADO.NET EF.&lt;/p&gt;
&lt;p&gt;The way my Flex application will consume data is over a web service, and we&amp;#8217;ll use WCF as our platform. It&amp;#8217;s easy to write and understand and ASP.NET has no issues delivering data over SOAP 1.1 or 1.2. There are lessons learned in this, so stay tuned.&lt;/p&gt;
&lt;p&gt;Flash Builder is really good at consuming data from many sources, especially via SOAP. ASP.NET will generate a WSDL for your Flex app to consume, however it has to be delivered via a SOAP 1.1 envelope, not 1.2. This is something you have to manually configure in the ASP.NET web.config file, or else you&amp;#8217;ll be scratching your head for a while.&lt;/p&gt;
&lt;p&gt;Once Flash Builder has consumed the WSDL, it will generate it&amp;#8217;s local objects and write all the code to handle the calls between client and server, without issue.&lt;/p&gt;
&lt;p&gt;In part 2, I&amp;#8217;ll jump into describing the back end of this equation on how the ASP.NET WCF Service code is constructed and some of the things learned to get it to work correctly.&lt;/p&gt;</description><link>http://allometry.com/post/13883218807</link><guid>http://allometry.com/post/13883218807</guid><pubDate>Wed, 07 Dec 2011 13:05:05 -0700</pubDate><category>ASP.NET</category><category>Flex</category><category>WCF Services</category><category>MSSQL</category></item><item><title>Fun with Sinatra</title><description>&lt;p&gt;I&amp;#8217;ve been a predominate PHP programmer for about ten years now, but my interest in Ruby was sparked about five years ago. I&amp;#8217;ve always followed Ruby as a web programming lang, but never had a project that would pay for my time to really get into what Ruby and it&amp;#8217;s &lt;a href="http://www.sinatrarb.com/" target="_blank"&gt;many&lt;/a&gt; &lt;a href="http://rubyonrails.org/" target="_blank"&gt;famous&lt;/a&gt; &lt;a href="http://www.merbivore.com/" target="_blank"&gt;frameworks&lt;/a&gt; can do.&lt;/p&gt;
&lt;p&gt;That is, until someone pissed me off.&lt;/p&gt;
&lt;p&gt;I probably should have let it go. However, I am easily annoyed by some folks who act like an authority on a subject, but obviously have no clue as to what they&amp;#8217;re talking about.&lt;/p&gt;
&lt;p&gt;The individual and specific conversation isn&amp;#8217;t important here, but some context will do you well. In my spit of rage (nearly putting my foot through the computer) I managed to get this guy banned from one of the forums, of which I&amp;#8217;m a regular. Not a permaban, but something to get his attention. Anyway, he registers another account, or so I think.&lt;/p&gt;
&lt;p&gt;To confirm my suspicion, I must get this guys IP address. Not easy to do, if you&amp;#8217;re several levels removed from direct access to your target. That&amp;#8217;s where Little Snoop comes in.&lt;/p&gt;
&lt;p&gt;Little Snoop is a small Ruby app with Sinatra running on top. It&amp;#8217;s backed by a Mongo DB and is drop dead simple. This post is for those of you, like me, who want to play with this stuff, but don&amp;#8217;t have someone around to get you involved, or you just don&amp;#8217;t have a lot of time.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/1439674" target="_blank"&gt;Here&amp;#8217;s the code&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/1439683" target="_blank"&gt;Some HAML&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Little Snoop works like this. You don&amp;#8217;t want your target to become suspicious of your actions, therefore you must keep a low profile. What&amp;#8217;s more low profile than a 1x1 transparent PNG?&lt;/p&gt;
&lt;p&gt;The request for this image is an action within the Little Snoop code, with the targets name acting as the key in the request string. When the target opens up a personal/private message with the image embedded, it logs their IP.&lt;/p&gt;
&lt;p&gt;In my case, all I have to do is send a non-sense message to both users on the forum and hope they open it. Then I can track, verify and confront (the rules on this forum don&amp;#8217;t allow for multiple accounts).&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s no security in Little Snoop and it&amp;#8217;s very wide open. There&amp;#8217;s no checks, validation or anything like that: it&amp;#8217;s just a dirty little application that gets the job done and was fun to write.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;</description><link>http://allometry.com/post/13838011322</link><guid>http://allometry.com/post/13838011322</guid><pubDate>Tue, 06 Dec 2011 13:45:05 -0700</pubDate><category>Ruby</category><category>Sinatra</category><category>Heroku</category></item><item><title>WHAT IS YOUR EARLIEST HUMAN MEMORY?</title><description>&lt;p&gt;Tinkering with the Millenium Falcon model hanging from the ceiling in my room. I think I was 3 or 4…&lt;/p&gt;</description><link>http://allometry.com/post/13834273984</link><guid>http://allometry.com/post/13834273984</guid><pubDate>Tue, 06 Dec 2011 12:10:46 -0700</pubDate></item><item><title>The Pit in Albuquerque. A very rare and thick fog set down on...</title><description>&lt;img src="http://25.media.tumblr.com/tumblr_lvspxyjgXD1r7jc1do1_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;The Pit in Albuquerque. A very rare and thick fog set down on top of the city on Saturday, December 3rd, 2011.&lt;/p&gt;</description><link>http://allometry.com/post/13833809763</link><guid>http://allometry.com/post/13833809763</guid><pubDate>Tue, 06 Dec 2011 11:56:00 -0700</pubDate><category>Lobos</category></item><item><title>Working with Animated GIFs</title><description>&lt;p&gt;Several month&amp;#8217;s ago, I wrote a small PHP script to generate an image representing a countdown clock. The image was static and was sufficient enough to meet my demands, knowing that refreshing the page would request a new image showing an updated time remaining clock.&lt;/p&gt;
&lt;p&gt;I used this image on this &lt;a href="http://thelobolair.com/" target="_blank"&gt;forum&lt;/a&gt; in my signature and it was a hit with the community. However, the script went to the next level when I was asked, &amp;#8220;why doesn&amp;#8217;t it count down? I always have to refresh.&amp;#8221;&lt;/p&gt;
&lt;p&gt;As a programmer, I set a goal to do something simple. Obviously using PHP GD is simple enough, but I hadn&amp;#8217;t even thought to animate the image. This is overkill for a vBulletin signature and normally I&amp;#8217;d solve this problem of a countdown with some javascript, but more often than not, you can&amp;#8217;t do that kind of stuff in a signature. The only way to fake it is to animate an image.&lt;/p&gt;
&lt;p&gt;Also, I learned a lesson in judging audience. It doesn&amp;#8217;t matter how simple the code is, or how proud you are of that simplicity; if it doesn&amp;#8217;t look cool, they don&amp;#8217;t care.&lt;/p&gt;
&lt;p&gt;The PHP script that generates an animated image is pretty simple and straight forward. The class I&amp;#8217;m using is GIFEncoder written by &lt;a href="http://gifs.hu" target="_blank"&gt;László Zsidi&lt;/a&gt;. I believe I found it on &lt;a href="http://www.phpclasses.org/" target="_blank"&gt;PHP Classes&lt;/a&gt;, an insufferable website to say the least.&lt;/p&gt;
&lt;p&gt;To animate an image, you first need to generate the frames to be animated. In the case of the countdown, each frame is held for 1 second for a total of 120 seconds before looping. This will sufficiently fake a 2-minute countdown, more than enough for the typical forum goer.&lt;/p&gt;
&lt;p&gt;Each image needs to be generated and captured to some sort of buffer in PHP. The only way to capture image output in PHP with GD is using the OB functions.&lt;/p&gt;
&lt;p&gt;After generating all the images, your GIFEncoder class can go to work. It can be a bit tricky to understand at first, however with my demonstration, it should be self explanatory.&lt;/p&gt;
&lt;p&gt;Basically, you&amp;#8217;re going to do this:&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;Generate your images and capture them to an array.&lt;/li&gt;
&lt;li&gt;Setup a secondary array within the same loop that contains the number of milliseconds a frame should be displayed.&lt;/li&gt;
&lt;li&gt;Create an instance of the GIFEncoder class, hand it the image buffer array, frames array, and pass in a few parameters (documented in the GIFEncoder class).&lt;/li&gt;
&lt;li&gt;Echo the output to the browser.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Here&amp;#8217;s a &lt;a href="https://gist.github.com/1438845" target="_blank"&gt;GIST&lt;/a&gt; of my demonstration. Here&amp;#8217;s a &lt;a href="https://gist.github.com/1438842" target="_blank"&gt;GIST&lt;/a&gt; of GIFEncoder class, since it seems to have gone bye-bye. Here&amp;#8217;s what your animated GIF can &lt;a href="http://dropbox.allometry.com/demo/countdown.php" target="_blank"&gt;look like&lt;/a&gt;.&lt;/p&gt;</description><link>http://allometry.com/post/13829542535</link><guid>http://allometry.com/post/13829542535</guid><pubDate>Tue, 06 Dec 2011 09:33:00 -0700</pubDate><category>PHP</category><category>Image Processing</category><category>GD</category><category>Snippets</category></item></channel></rss>

