<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>HTMList.com, A Web Development Blog by Synapse Studios</title>
	
	<link>http://www.htmlist.com</link>
	<description>A Web Development Blog by Synapse Studios</description>
	<lastBuildDate>Thu, 19 Jan 2012 09:30:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/HTMList" /><feedburner:info uri="htmlist" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" /><feedburner:emailServiceId>HTMList</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>Olark: Live Chat Made Amazing (and Simple!)</title>
		<link>http://feedproxy.google.com/~r/HTMList/~3/_UnpELBKa7s/</link>
		<comments>http://www.htmlist.com/cool-stuff/olark-live-chat-made-amazing-and-simple/#comments</comments>
		<pubDate>Thu, 19 Jan 2012 09:30:04 +0000</pubDate>
		<dc:creator>Chris Cardinal</dc:creator>
				<category><![CDATA[Cool Stuff]]></category>
		<category><![CDATA[Reviews]]></category>
		<category><![CDATA[olark]]></category>

		<guid isPermaLink="false">http://www.htmlist.com/?p=647</guid>
		<description><![CDATA[Whilst in the throes of exploring my favorite airfare booking site (Hipmunk), I noticed their live chat tool looked a little&#8230; different. It was bouncy, fun, and unassuming. Turns out, they use Olark: by far the most impressive live chat tool I&#8217;ve ever had the pleasure of dealing with. Olark is absolutely simple to integrate: a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.olark.com/?r=xbmkh5ky"><img class="alignleft" title="Olark Logo" src="http://www.olark.com/images/sky/common/logo-medium-3d.png" alt="Olark Logo" width="207" height="134" /></a>Whilst in the throes of exploring my favorite airfare booking site (<a title="Hipmunk" href="http://www.hipmunk.com">Hipmunk</a>), I noticed their live chat tool looked a little&#8230; different. It was bouncy, fun, and unassuming. Turns out, they use <strong><a title="Olark" href="http://www.olark.com/?r=xbmkh5ky">Olark</a></strong>: by far the most impressive live chat tool I&#8217;ve ever had the pleasure of dealing with.</p>
<p>Olark is absolutely simple to integrate: a single snippet of JavaScript. But it offers a great deal of power: you can push a logged in user&#8217;s name and email address through the chat, and set their IP address, browser build, and other details as that user&#8217;s &#8220;status&#8221; when chatting. (You can even have the chat bot message you that information at the beginning of the session.)</p>
<p>The fun doesn&#8217;t end there: Olark allows you to actually redirect a user to a different URL, including external addresses, all while maintaining persistent chat. This is absolutely fantastic, as you can literally direct a user to the page they need while still helping them out. Olark reports what page they&#8217;re currently looking at, and their new co-browsing feature allows you to literally see what your users see, scroll the page for them, and circle certain elements.</p>
<p>This level of interaction is fantastic: it can help clinch a waffling pre-sale customer who has a small question but isn&#8217;t able to find an answer and doesn&#8217;t want to go through the trouble of filling out a contact form. Or it can assist with the on-boarding process: new users are the most likely to encounter experience-ruining burrs, problems, small barriers to entry that can be resolved with a simple chat.</p>
<p>The ability to transfer conversations, native Jabber/XMPP utilization (such that I can use Trillian for managing my chats), and a robust API round out the core features of a very compelling product. Olark is free for up to 20 conversations a month and one operator, but the clients we&#8217;ve signed up on Olark needed the Gold plan, since it&#8217;s the lowest plan that supports SSL.</p>
<p>Check out Olark for pre-sale potential customer engagement, and post-sale onboarding/getting started assistance. Reducing friction for new and potential users is the surest way to build a loyal following or make a sale.</p>
<p><a title="Olark live chat" href="http://www.olark.com/?r=xbmkh5ky">Olark</a></p>
<img src="http://www.htmlist.com/wordpress/?ak_action=api_record_view&id=647&type=feed" alt="" />
<p><a href="http://feedads.g.doubleclick.net/~a/DbTv514bCZB62uIPDLnvBjSErkU/0/da"><img src="http://feedads.g.doubleclick.net/~a/DbTv514bCZB62uIPDLnvBjSErkU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/DbTv514bCZB62uIPDLnvBjSErkU/1/da"><img src="http://feedads.g.doubleclick.net/~a/DbTv514bCZB62uIPDLnvBjSErkU/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/HTMList/~4/_UnpELBKa7s" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.htmlist.com/cool-stuff/olark-live-chat-made-amazing-and-simple/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.htmlist.com/cool-stuff/olark-live-chat-made-amazing-and-simple/</feedburner:origLink></item>
		<item>
		<title>Fun in Source Code with Off And Away</title>
		<link>http://feedproxy.google.com/~r/HTMList/~3/S6WSuxRseYU/</link>
		<comments>http://www.htmlist.com/development/fun-in-source-code-with-off-and-away/#comments</comments>
		<pubDate>Thu, 14 Jul 2011 01:50:24 +0000</pubDate>
		<dc:creator>Chris Cardinal</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[comments]]></category>
		<category><![CDATA[off and away]]></category>

		<guid isPermaLink="false">http://www.htmlist.com/?p=641</guid>
		<description><![CDATA[A look at travel site Off and Away's source code reveals that everyone sneaks in fun lines in their source code from time to time.]]></description>
			<content:encoded><![CDATA[<p><a href="http://bit.ly/qQg5RO"><img class="aligncenter size-full wp-image-642" title="shizzle" src="http://www.htmlist.com/wordpress/wp-content/uploads/2011/07/shizzle.png" alt="" width="511" height="408" /></a></p>
<p><a href="http://bit.ly/qQg5RO">Off and Away</a> is a neat travel bidding site that lets you bid on travel deals for pennies. (The bids cost roughly a buck, though.) Curious at how their timer was put together, biz-partner Bob took a peek at their JavaScript. Somewhat surprised to find that they hadn&#8217;t <a href="http://en.wikipedia.org/wiki/Minification_(programming)">minified</a> it, he was even more amused by their credit card function, aptly named <span style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace; line-height: 18px; white-space: pre;">$.fn.creditcard_shizzle.</span></p>
<p>When writing and testing code, it&#8217;s really tempting to put in junk data or in-jokes or other fun bits. As a development company, we&#8217;ve banned that outright, even in development environments, because we&#8217;ve discovered that somehow, some way, our little joke will end up live, released to clients or their customers, or even worse, appear in big bold letters in the middle of a demo. Nothing quite matches the sheer terror and stomach-pit feeling as having &#8220;stupid mcassface&#8221; show up during a demo.</p>
<p>Clearly, Off and Away&#8217;s devs/founders have a sense of humor and since this is source code and not customer-facing, this isn&#8217;t really a big deal. It&#8217;s not even vulgar. But it&#8217;s amusing to stumble across these sort of gems, as long as they&#8217;re not in the middle of a demo. For more fun, search swear words on <a href="http://www.google.com/codesearch">Google&#8217;s Code Search</a>. You&#8217;ll find some exasperated comments, angry rants, and outright bitterness, to be sure. (Hell, <a href="http://www.kuro5hin.org/story/2004/2/15/71552/7795">even Microsoft&#8217;s done it</a>.)</p>
<p><a href="http://bit.ly/qQg5RO">Off and Away</a></p>
<img src="http://www.htmlist.com/wordpress/?ak_action=api_record_view&id=641&type=feed" alt="" />
<p><a href="http://feedads.g.doubleclick.net/~a/gnbXsAIFuIPPtZSI1UaJRgDnLnQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/gnbXsAIFuIPPtZSI1UaJRgDnLnQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/gnbXsAIFuIPPtZSI1UaJRgDnLnQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/gnbXsAIFuIPPtZSI1UaJRgDnLnQ/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/HTMList/~4/S6WSuxRseYU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.htmlist.com/development/fun-in-source-code-with-off-and-away/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.htmlist.com/development/fun-in-source-code-with-off-and-away/</feedburner:origLink></item>
		<item>
		<title>Where Google+ Goes From Here</title>
		<link>http://feedproxy.google.com/~r/HTMList/~3/1PQ1SAouvv8/</link>
		<comments>http://www.htmlist.com/cool-stuff/where-google-plus-goes-from-here/#comments</comments>
		<pubDate>Mon, 04 Jul 2011 17:22:55 +0000</pubDate>
		<dc:creator>Chris Cardinal</dc:creator>
				<category><![CDATA[Cool Stuff]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[google plus]]></category>
		<category><![CDATA[Social Networking]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://www.htmlist.com/?p=638</guid>
		<description><![CDATA[Google's Plus represents their best effort in the social networking space. So what do they need to do to really lock things down?]]></description>
			<content:encoded><![CDATA[<p><a href="http://plus.google.com/"><img class="alignright" title="Google Plus" src="https://ssl.gstatic.com/s2/oz/intl/en-US/images/slide2-57662827ca642dc8b654937eb7231272.png" alt="Google Plus" width="346" height="227" /></a></p>
<p>Google&#8217;s Plus release represents their first legitimate effort at a coherent social experience. Right out of the gate, they&#8217;ve got a few things incredibly right: amazing notifications unified throughout all Google products, good integration with Picasa and Android, Circles, Hangouts, data portability, and a feeling like this might be around for some time.</p>
<p>Now they need to focus on what&#8217;s necessary to make this a second nature, everyday product for people, like Facebook is now for most people.</p>
<p><strong>Open Registrations/Invitations</strong></p>
<p>If anyone can get scale right, it should be Google. Admittedly, scaling instantly in to the millions is a challenge for even the largest companies, and there&#8217;s surely a method to their madness here, but they need to be doing whatever they can to get this thing open to as many people as possible. They&#8217;re framing the current experience as a &#8220;Field Test&#8221;, but it&#8217;s difficult to test a social networking product if you can&#8217;t get your friends onto it. Early adopters are the type of user who will shift their more reluctant friends to a new system. They&#8217;re kneecapping their momentum with their limited invitations.</p>
<p><strong>Figure Out Sparks</strong></p>
<p>By far, the most confusing element of Plus is Sparks. It&#8217;s an interesting hodgepodge auto-aggregator of news and blog posts on individual topics (or &#8220;eccentric hobbies&#8221; as their video goes), but it&#8217;s presented in a bit of a sloppy way. Since it&#8217;s curated automatically, it&#8217;s not terribly great at it, which is a bit disappointing as well. Fortunately, Sparks is a nice-to-have within the Plus experience. Perhaps some integration with Reader would help make Sparks shine.</p>
<p><strong>Make Huddles Amazing (Read: Copy Beluga)</strong></p>
<p>I&#8217;ve got basically every single friend I speak with regularly on Beluga now. We use it to plan events, see what&#8217;s happening for the evening, and coordinate shared rides and the like. It&#8217;s a great tool. We also have fun with it. We share photos and links and such. And we can access it from our desktop if necessary. Huddles don&#8217;t currently let you access them from the Plus site itself, only from the mobile app. Since Plus isn&#8217;t available in the iPhone App Store yet, I can&#8217;t try to convert my friends to Huddles yet. And since Huddles don&#8217;t let us share photos or set Huddle photos, I don&#8217;t know if I&#8217;d want to yet. Location sharing is really useful too, and here Google has a definite leg up: it already shares location on posts&#8230; why not on huddle updates? Moreover, why not tie directly in to Latitude? Let me navigate right to a real-time-updating friend if I&#8217;m picking them up from someone, right from within our Huddle!</p>
<p><strong>Import Profile Pics from&#8230; Somewhere!</strong></p>
<p>Most of my connections/friends on Plus are faceless. Make adding a profile picture a required first step. It&#8217;s important to associate faces with names, but moreover, it&#8217;s WAY less usable to see a bunch of placeholder graphics throughout the product. Import from Gravatar, or, if you won&#8217;t violate TOS (heh), from Facebook directly. Either way, make it required, or constantly nag until it gets done.</p>
<p><strong>Release a Stream Notifier or API</strong></p>
<p>If you want us to engage, we need to know things are happening. Right now, it appears the only way to see new posts is to load up the Plus site or app and look at the Streams. Facebook and Twitter have apps or APIs that allow us to get pinged with updates as they happen. You&#8217;ll lose momentum and people will stop coming back to Plus if we can&#8217;t see what&#8217;s happening without having to call up the site manually every time.</p>
<p><strong>Let Me Cross-Post Content Easily</strong></p>
<p>Since Plus isn&#8217;t going to overtake Facebook, Twitter, or Linked In overnight, let me cross-post to those places with a click of a button. Better yet, blow everyone away and make it as easy as choosing a &#8220;Circle&#8221;. Add the Facebook &#8220;Circle&#8221; and the post auto-cross-posts there. Add the Twitter &#8220;Circle&#8221; and the shortened form is available for preview before it ends up there. By keeping up the walled garden, Google may be intentionally discouraging this sort of behavior, but this is what will trigger buy-in immediately and ease the transition. Social networks aren&#8217;t necessarily a zero-sum game, but two is likely very close to the limit for most.</p>
<p><strong>What&#8217;s Next for Plus</strong></p>
<p>Plus is off to a great start. Better than Buzz or Google Wave could ever hope for. It&#8217;s exciting, clean, original, and well-executed, with a lot of great features available right out of the gate, and some really innovative concepts. With a bit of polish and a bit more hand-holding, I think Google can convince people to begin using Plus as part of their daily interaction. But the elements needed to keep us checking in and coming back every day aren&#8217;t quite there yet. The notifications are a great start, but they only tell part of the story, keeping me informed only after I&#8217;ve already engaged. I need a reminder to check in on Plus and see that my friends are using it, and that&#8217;s sorely lacking right now.</p>
<p>Google also needs to integrate single-sign-on/Google Authentication with Plus, the way Facebook Connect can be used to allow people to log in or register on a site. It&#8217;s not necessary to have a complete app platform available right out of the gate, but Facebook is definitely on to something with Facebook Connect and it&#8217;s an important element for any social networking site to drive engagement.</p>
<p>Hopefully we&#8217;ll see swift continued development on Plus. It&#8217;s a great product out of the gate, but building the product isn&#8217;t the hard part in social networking: that&#8217;s left to getting users to buy in and keep coming back for more. Plus solves a lot of the qualms people have with Facebook on the privacy, data portability, account deletion, and sharing side of things, and that&#8217;s amazing. But it&#8217;s not an instant win, and they&#8217;ve got a long way to go. Making Huddles indispensible (and consider integrating them with group gTalk) would help, but I&#8217;m hoping they&#8217;ve got some other unique features up their sleeves to introduce into the Plus fold. I&#8217;m disappointed that the Slide-inside-Google-developed Pool Party and Prizes products weren&#8217;t built with Plus in mind. It might be time for the left hand to clue the right hand into what&#8217;s going on, and to get everyone on the same page.</p>
<p><strong><br />
</strong></p>
<img src="http://www.htmlist.com/wordpress/?ak_action=api_record_view&id=638&type=feed" alt="" />
<p><a href="http://feedads.g.doubleclick.net/~a/7jcjTwfolLcAZXR_edQxWrQYRrc/0/da"><img src="http://feedads.g.doubleclick.net/~a/7jcjTwfolLcAZXR_edQxWrQYRrc/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/7jcjTwfolLcAZXR_edQxWrQYRrc/1/da"><img src="http://feedads.g.doubleclick.net/~a/7jcjTwfolLcAZXR_edQxWrQYRrc/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/HTMList/~4/1PQ1SAouvv8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.htmlist.com/cool-stuff/where-google-plus-goes-from-here/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.htmlist.com/cool-stuff/where-google-plus-goes-from-here/</feedburner:origLink></item>
		<item>
		<title>Synapse Studios Client “Nestablish” Launches</title>
		<link>http://feedproxy.google.com/~r/HTMList/~3/cj57EpvXE9g/</link>
		<comments>http://www.htmlist.com/announcements/synapse-studios-client-nestablish-launches/#comments</comments>
		<pubDate>Thu, 10 Mar 2011 08:44:04 +0000</pubDate>
		<dc:creator>Chris Cardinal</dc:creator>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[clients]]></category>
		<category><![CDATA[launch]]></category>
		<category><![CDATA[launching]]></category>
		<category><![CDATA[nestablish]]></category>
		<category><![CDATA[projects]]></category>

		<guid isPermaLink="false">http://www.htmlist.com/?p=631</guid>
		<description><![CDATA[Synapse Studios launches startup Nestablish, a loan workflow management tool for loan officers, real estate agents, and home buyers.]]></description>
			<content:encoded><![CDATA[<p style="text-align:center;"><a href="http://www.nestablish.com/"><img class="aligncenter size-full wp-image-632" title="Nestablish: Loan Officer Workflow Management System" src="http://www.htmlist.com/wordpress/wp-content/uploads/2011/03/nestablish_screen.png" alt="" width="450" height="333" /></a></p>
<p>HTMList primarily focuses on the technical side of the web development work we do here at <a title="arizona web development and custom software" href="http://www.synapsestudios.com/">Synapse Studios</a>. We&#8217;re mixing things up a bit with the announcement of the launch of Nestablish.com, a comprehensive <a title="loan officer workflow management" href="http://www.nestablish.com/">loan officer workflow management</a> system, built as a startup for a few loan officers who wanted to make life easier for their fellow loan officers.</p>
<p>Loan officers frequently have to generate and sign pre-qualification forms and other specialty forms (such as <a title="Arizona Loan Status Update for Nestablish" href="https://nestablish.com/how-it-works/loan-officer">Arizona&#8217;s Loan Status Update</a> form) for each and every offer a real estate agent makes on a house. This can often come at inconvenient times, such as nights and weekends, when loan officers are typically off-the-clock. Nestablish allows loan officers to configure a maximum value for the pre-qualification documentation. The real estate agent is then granted the ability to generate the forms at the value they require, automatically limited to the maximum allowed by the loan officer.</p>
<p>This project presented a few interesting challenges for us, including working with the Fannie Mae 3.2 file specification to allow for the easy import of loan information into the system, and some complex PDF generation. Since each loan flows through a complex process with a lot of steps and required documents, we built Nestablish to allow the loan officer, real estate agent, and home buyer alike to track the progress on the loan approval and see exactly where they are in the process. This ensures faster closings with fewer back-and-forth during the typically-stressful home buying process.</p>
<p>We&#8217;re incredibly proud of our team here at Synapse who helped make Nestablish a reality, including Jeremy Lindblom, Andrew Reida, and Bob Eagan. We&#8217;ll be working with the fantastic team at Nestablish to deliver a whole new suite of features to the site very soon, but loan officers can get started today by <a title="Nestablish Loan Workflow Free Trial" href="https://nestablish.com/account/register/officer">registering for a free 60-day trial</a>. (Nestablish is free for real estate agents and home buyers, and only $29.95 for loan officers after the free trial.)</p>
<p><a title="Nestablish: Loan Workflow Management" href="http://www.nestablish.com">Nestablish — Loan Workflow Management &amp; Form Generation</a></p>
<img src="http://www.htmlist.com/wordpress/?ak_action=api_record_view&id=631&type=feed" alt="" />
<p><a href="http://feedads.g.doubleclick.net/~a/I-IlKHrKniIlO9lMGHv8LDkKxtg/0/da"><img src="http://feedads.g.doubleclick.net/~a/I-IlKHrKniIlO9lMGHv8LDkKxtg/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/I-IlKHrKniIlO9lMGHv8LDkKxtg/1/da"><img src="http://feedads.g.doubleclick.net/~a/I-IlKHrKniIlO9lMGHv8LDkKxtg/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/HTMList/~4/cj57EpvXE9g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.htmlist.com/announcements/synapse-studios-client-nestablish-launches/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.htmlist.com/announcements/synapse-studios-client-nestablish-launches/</feedburner:origLink></item>
		<item>
		<title>Better Group (And Personal) Password Management with KeePass &amp; Dropbox</title>
		<link>http://feedproxy.google.com/~r/HTMList/~3/UDNlo7v4TfI/</link>
		<comments>http://www.htmlist.com/cool-stuff/better-group-password-management-with-keepass-dropbox/#comments</comments>
		<pubDate>Wed, 26 Jan 2011 05:58:12 +0000</pubDate>
		<dc:creator>Chris Cardinal</dc:creator>
				<category><![CDATA[Cool Stuff]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[dropbox]]></category>
		<category><![CDATA[encryption]]></category>
		<category><![CDATA[group passwords]]></category>
		<category><![CDATA[keepass]]></category>
		<category><![CDATA[password management]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.htmlist.com/?p=627</guid>
		<description><![CDATA[Managing multiple passwords within a group while maintaining security, good practices, and synchronization can be a challenge. We explore our utilization of a program called KeePass and a file-sharing system called Dropbox to help manage passwords.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.htmlist.com/wordpress/wp-content/uploads/2011/01/main.jpg"><img class="alignleft size-full wp-image-628" title="KeePass Screenshot" src="http://www.htmlist.com/wordpress/wp-content/uploads/2011/01/main.jpg" alt="" width="300" height="206" /></a>As a <a title="Phoenix, Arizona Web Development &amp; Design &amp; Custom Software" href="http://www.synapsestudios.com/">web development firm</a>, we frequently have to manage passwords and other credentials for multiple clients and their projects. This includes everything from SFTP and SSH information, database passwords, DNS managers, domain registrars, and everything else under the sun. We&#8217;ve moved to a policy of good password practice across the board at the urging of common sense, and one of our former developers, <a href="http://alanhogan.com/">Alan Hogan</a>. (Our previous system was not sharable, and wrought with other shortcomings.)</p>
<p>We needed a password system that was secure but which would allow us to share client passwords across our team, while ensuring limited access within the organization, and unique, complex passwords every single time. We ended up making use of the wonderful <a href="http://www.keepass.info">KeePass</a> tool, synced through <a title="Dropbox" href="http://db.tt/iFL8DPs">Dropbox</a>.</p>
<p>KeePass is a wonderful password manager (though not as much for Mac or Linux users, for reasons I&#8217;ll get to) in general. And it has some pretty great features, some unique to KeePass, others relatively standard fare:</p>
<p><span id="more-627"></span></p>
<p><strong>Strong Security</strong><br />
Clearly, any good password manager needs to be secure itself. KeePass supports AES and TwoFish, amongst other encryption standards that are very difficult to crack. Your password database is duly encrypted thusly. Further, you can expand your security by requiring the use of a unique key file in addition to (or instead of, though this isn&#8217;t recommended) the password you use to unlock the database. This adds an additional layer of security against things like keyloggers, in that the hacker must have access to and identify the key file to use, in addition to knowing or cracking your password. (A strong password is still important, since simple passwords will fall to <a href="http://en.wikipedia.org/wiki/Dictionary_attack">dictionary attacks</a> relative quickly.) You can also use your Windows login to unlock your database, but again, this shouldn&#8217;t be your only method to unlock, and this doesn&#8217;t work when sharing a password database as we do.</p>
<p>KeePass also goes to some length to keep your passwords completely out of process memory. This keeps malicious software from identifying passwords in the memory stream of the process while it&#8217;s running. It also can be configured to automatically purge the computer&#8217;s clipboard after a set period of time, to prevent a user from walking up to your computer and hitting paste and hoping for the best.</p>
<p><strong>Workspace Locking</strong><br />
Workspace locking goes hand-in-hand with strong security, itself being a subset of the program&#8217;s security. You can easily configure KeePass to automatically re-lock your database after a period of system OR KeePass inactivity, when the software is minimized, or when your workstation itself is locked. (I&#8217;ve noticed that it can sometimes pause the locking process when the database has changed, though this might have been resolved in recent updates.)</p>
<p><strong>Intelligent Sync Management</strong><br />
KeePass surprised me with its intelligent management of file changes. If a user on my team alters the KeePass file (which is stored to a Dropbox folder we all have access to) while I&#8217;m using the file, it prompts that it can merge the changes with any changes you may have made. Unless both of us happened to be editing the same record, the merge typically works perfectly, ensuring that all of our changes are current.</p>
<p><strong>Our Process</strong><br />
We store our KeePass file on our team&#8217;s Dropbox folder. We have a very strong password applied to that file, which we change frequently. We also require the use of a key file to unlock the database, which is NOT stored in our Dropbox. This file is distributed manually and only on a few systems. We also maintain several different databases, based on what access a user needs. Unfortunately, there isn&#8217;t a way to share a record amongst databases in order to keep it current, so this sort of functionality only goes so far, but if necessary, we&#8217;re able to quickly change all of the passwords we need to in the event of a personnel change or other problem.</p>
<p>Dropbox syncs the file as I described above, ensuring we&#8217;re all working off of the same copy of the file. If we wanted to, we could enforce a read-only rule that would have one member of the team making all password changes and entries, but this wouldn&#8217;t be very efficient for our team, and we trust our team members.</p>
<p><strong>Potential Issues</strong><br />
Unfortunately, KeePass isn&#8217;t built to play terribly kindly with OS X or Linux. KeePass is kept in two development variants: 1.x and 2.x, with 1.x being Windows- and WINE-compatible, but missing some great features, and 2.x only working in Mono, to varying degrees of success (as far as those in our organization were concerned.) A solution to this is <a href="http://www.keepassx.org/">KeePassX</a>, which works natively in OS X/Linux, but which doesn&#8217;t support the kdbx file format used by 2.x. The KeePassX developer is looking to rebuild it to support kdbx, so hopefully we&#8217;ll see that problem reconciled in time, but for now, Mono may be your best bet, if you can get it to cooperate.</p>
<p><strong>Neat Bonuses</strong><br />
KeePass has a pretty great Android app that can work together with the Dropbox app to load your database, even if it requires both the password AND key file. I haven&#8217;t had a chance to use the iOS apps, but apparently they&#8217;re pretty nice as well. I generally use this in read-only mode exclusively, but it&#8217;s convenient nonetheless when you absolutely *need* a password. There&#8217;s also a plugin system that allows for some cool extensibility, and it&#8217;s actively being developed, so you&#8217;ll see updates hit on a regular basis. It&#8217;s also entirely free.</p>
<p>You can easily sort passwords into folders and sub-folders, assign icons to them, search through records, attach other encrypted data to each record, store record histories, and even have it perform a macro of keystrokes when &#8220;auto-typing&#8221; your password in. (This is useful if you need to select a database, for instance, from a dropdown. You can even have it launch a new browser tab, browse to the page in question, and go from there, though this requires a bit of configuration to get working.)</p>
<p><strong>Conclusion<br />
</strong>Overall, we&#8217;ve been very happy with KeePass. We weren&#8217;t willing to take the plunge and use an online, hosted solution to store our passwords, if we could avoid it. Because we control the encryption and access requirements, and because Dropbox is pretty secure in and of itself, I feel comfortable keeping our password database on Dropbox, encrypted with AES-256 bit on a strong password, and backed by a non-Dropboxed encryption key.</p>
<p>This is a somewhat unique configuration for our smaller group, and you&#8217;ll likely need to modify it accordingly, but hopefully this can give you a great starting place for good password management with your team.</p>
<p><a href="http://keepass.info/index.html">KeePass Password Manager</a> (free!)</p>
<p><a href="http://db.tt/iFL8DPs">Dropbox</a> (free!)</p>
<img src="http://www.htmlist.com/wordpress/?ak_action=api_record_view&id=627&type=feed" alt="" />
<p><a href="http://feedads.g.doubleclick.net/~a/KtvJzBMzyWgqOMqJC2-k9KISXwo/0/da"><img src="http://feedads.g.doubleclick.net/~a/KtvJzBMzyWgqOMqJC2-k9KISXwo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/KtvJzBMzyWgqOMqJC2-k9KISXwo/1/da"><img src="http://feedads.g.doubleclick.net/~a/KtvJzBMzyWgqOMqJC2-k9KISXwo/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/HTMList/~4/UDNlo7v4TfI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.htmlist.com/cool-stuff/better-group-password-management-with-keepass-dropbox/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.htmlist.com/cool-stuff/better-group-password-management-with-keepass-dropbox/</feedburner:origLink></item>
		<item>
		<title>8 Simple Tips For Making A Restaurant Web Site That Doesn’t Suck</title>
		<link>http://feedproxy.google.com/~r/HTMList/~3/sC1PN11NUDE/</link>
		<comments>http://www.htmlist.com/design/8-simple-tips-for-making-a-restaurant-web-site-that-doesnt-suck/#comments</comments>
		<pubDate>Sun, 26 Sep 2010 08:35:18 +0000</pubDate>
		<dc:creator>Chris Cardinal</dc:creator>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[design tips]]></category>
		<category><![CDATA[food service]]></category>
		<category><![CDATA[menus]]></category>
		<category><![CDATA[restaurant sites]]></category>
		<category><![CDATA[restaurants]]></category>

		<guid isPermaLink="false">http://www.htmlist.com/?p=622</guid>
		<description><![CDATA[We list some simple tips for building a great web site for a restaurant.]]></description>
			<content:encoded><![CDATA[<p>Restaurant web sites are an interesting beast. It&#8217;s 2010. By now, nearly every restaurant realizes they need a web site. Unfortunately, a lot of owners still don&#8217;t quite understand what purpose their site serves or how to best serve their potential customers.</p>
<p>I&#8217;ll keep this simple:</p>
<ol>
<li>Your full address, hours, and phone number should appear on EVERY SINGLE PAGE, please. Don&#8217;t make me hunt for this information, since this is what at least 90% of your visitors are hunting for. Jam it into a sidebar or footer, but do NOT make me click a separate link or search like a truffle pig for something so very basic.</li>
<li>Put a map on your contact page. Don&#8217;t just link to it, put the damn map there. This is extraordinarily simple, and <a href="http://maps.google.com/help/maps/getmaps/quick.html">full instructions are here</a>, but suffice to say, enter your address on Google maps, click the Link option in the upper right corner, and copy and paste the embed code that appears. Don&#8217;t make me click through to see the map.</li>
<li>Stop using Flash. Just stop. Resist the urge. It doesn&#8217;t make you edgy. It annoys the hell out of me. And any of your users who are trying to pull your site up on their phones. You can accomplish cool image changing effects in other ways, and if you&#8217;re playing music, that needs to stop too. Save the ambiance for your restaurant. Flash is also exquisitely bad for search engine optimization; people searching for a specific dish or words and phrases that would otherwise appear on your site may not find them if the search engines have trouble grabbing them. They&#8217;ve gotten better at searching Flash, but it&#8217;s still nearly impossible to drop someone accurately to the right spot in your Flash movie, so it just frustrates people.</li>
<li>Make your full menu available. With prices. And incredibly prominently. The 10% of users who already know where you are and when you&#8217;re open are coming to check your menu. If you have several menus, list each of them. If they change often, that&#8217;s fine, but keep it seasonally representative at the very least.</li>
<li>Make your menu available in a manner other than PDF. I know this one is a toughy and it&#8217;s unlikely to be a change anyone adopts in the near future. Restaurant owners are busy people who barely have the time to update the menu in PDF form, which is how they get it printed, to worry about converting it to HTML or making it otherwise available on the site in a way that looks half decent. But doing this the right way is better for search engines, mobile users, and people who know that opening a PDF is a sometimes-Sisyphean ordeal that causes you to curse the gods. Don&#8217;t put us through that. We want to plan our meals or see if you have something we like. Make it easier on us.</li>
<li>Only show fantastic food photos. Pay a photographer to get it right if you must, but do NOT post cell phone pictures from your Blackberry that you took on the patio at 11pm. This reflects poorly on your presentation even if the dish looks fantastic in person, and there&#8217;s no need to give people a specific reason NOT to show up. Also, you need not over-emphasize photos. While fantastic photos can really help push someone the right direction, you don&#8217;t need to overwhelm them. This isn&#8217;t McDonalds. In any event, make sure they&#8217;re great quality photos: well-lit, not overly compressed, and of something appetizing and plated well.</li>
<li>Make sure you list things that set you apart. If you offer dietary considerations for diabetic, gluten-free, kosher, vegetarians, or vegan dieters, mention that. It&#8217;ll help in search engine results, and it&#8217;s invaluable for people who are looking specifically for that information and are unsure if you have anything that works for them. Consider whipping up an online menu that showcases some of those dishes; people in those communities will be extremely appreciative.</li>
<li>Give us a little personality. Clearly state your purpose, your passion, and what you do to deliver and set yourself apart. A simple explanation with a few well-written bits about how much you love making great food for people can get your visitors energized and ready to make a reservation.</li>
</ol>
<p>These are pretty universal, simple to apply tips that can enhance the experience for visitors who need a very specific piece of information typically very quickly: don&#8217;t frustrate us by burying it, forgetting to supply it entirely, or by designing the site so horribly that it&#8217;s nearly closing time when we finally track down your hours.</p>
<img src="http://www.htmlist.com/wordpress/?ak_action=api_record_view&id=622&type=feed" alt="" />
<p><a href="http://feedads.g.doubleclick.net/~a/cy9JSwMl4eaAdvxludevp4LwOoU/0/da"><img src="http://feedads.g.doubleclick.net/~a/cy9JSwMl4eaAdvxludevp4LwOoU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/cy9JSwMl4eaAdvxludevp4LwOoU/1/da"><img src="http://feedads.g.doubleclick.net/~a/cy9JSwMl4eaAdvxludevp4LwOoU/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/HTMList/~4/sC1PN11NUDE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.htmlist.com/design/8-simple-tips-for-making-a-restaurant-web-site-that-doesnt-suck/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.htmlist.com/design/8-simple-tips-for-making-a-restaurant-web-site-that-doesnt-suck/</feedburner:origLink></item>
		<item>
		<title>Just another day in a Skype room with programmers…</title>
		<link>http://feedproxy.google.com/~r/HTMList/~3/AyO1QAWw-u8/</link>
		<comments>http://www.htmlist.com/cool-stuff/skype-fun-with-programmers/#comments</comments>
		<pubDate>Fri, 27 Aug 2010 05:14:10 +0000</pubDate>
		<dc:creator>Chris Cardinal</dc:creator>
				<category><![CDATA[Cool Stuff]]></category>
		<category><![CDATA[chat logs]]></category>
		<category><![CDATA[mana]]></category>
		<category><![CDATA[skype]]></category>

		<guid isPermaLink="false">http://www.htmlist.com/?p=619</guid>
		<description><![CDATA[Skype is a great internal tool for managing projects and chatting with team members. Sometimes to hilarious result.]]></description>
			<content:encoded><![CDATA[<div id="_mcePaste">
<div><span style="color: #ff0000;">Bob E</span>: lorenzo, there were also some validation lang keys missing for image upload validation stuff, so if you can add those too that would be good</div>
<div id="_mcePaste"><span style="color: #0000ff;">Lorenzo P</span>: not possible</div>
<div id="_mcePaste"><span style="color: #0000ff;">Lorenzo P</span>: can&#8217;t be done</div>
<div id="_mcePaste"><span style="color: #0000ff;">Lorenzo P</span>: not enough mana.</div>
<div id="_mcePaste"><span style="color: #339966;">David B</span>: tough break, bob</div>
<div id="_mcePaste"><span style="color: #ff0000;">Bob E</span>: not really, now that i know he is out of mana i&#8217;m going to attack</div>
<div id="_mcePaste"><span style="color: #0000ff;">Lorenzo P</span>: I&#8217;m obviously a barbarian you FOOL!</div>
<div id="_mcePaste"><span style="color: #0000ff;">Lorenzo P</span>: should I auto login users on activation while I&#8217;m at it?</div>
<div id="_mcePaste"><span style="color: #ff0000;">Bob E</span>: sure</div>
<div></div>
</div>
<div>We use Skype for inter-office communication a lot. We&#8217;ve found it a nice tool for building chat rooms for specific projects, to keep things separated and clean; we can invite clients to discuss things throughout the day, and file sharing is simplified. I&#8217;ll save my critiques for Skype&#8217;s complete inane shortcomings across basically every platform for another post, but suffice to say, occasionally we have exchanges like the one above.</div>
<div></div>
<div>Please remember to ensure an adequate mana supply for your developers at all times.</div>
<img src="http://www.htmlist.com/wordpress/?ak_action=api_record_view&id=619&type=feed" alt="" />
<p><a href="http://feedads.g.doubleclick.net/~a/7sz0ncyK8cxXUZHClgQHcrwP-kc/0/da"><img src="http://feedads.g.doubleclick.net/~a/7sz0ncyK8cxXUZHClgQHcrwP-kc/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/7sz0ncyK8cxXUZHClgQHcrwP-kc/1/da"><img src="http://feedads.g.doubleclick.net/~a/7sz0ncyK8cxXUZHClgQHcrwP-kc/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/HTMList/~4/AyO1QAWw-u8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.htmlist.com/cool-stuff/skype-fun-with-programmers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.htmlist.com/cool-stuff/skype-fun-with-programmers/</feedburner:origLink></item>
		<item>
		<title>Newsletter Frequency: Let Users Decide</title>
		<link>http://feedproxy.google.com/~r/HTMList/~3/A5ZKWhN8drM/</link>
		<comments>http://www.htmlist.com/rants/newsletter-frequency-let-users-decide/#comments</comments>
		<pubDate>Sun, 15 Aug 2010 08:03:10 +0000</pubDate>
		<dc:creator>Chris Cardinal</dc:creator>
				<category><![CDATA[Rants]]></category>
		<category><![CDATA[cb2]]></category>
		<category><![CDATA[crate and barrel]]></category>
		<category><![CDATA[customer engagement]]></category>
		<category><![CDATA[email newsletters]]></category>
		<category><![CDATA[harry and david]]></category>
		<category><![CDATA[marketing]]></category>
		<category><![CDATA[newsletters]]></category>
		<category><![CDATA[online marketing]]></category>
		<category><![CDATA[west elm]]></category>

		<guid isPermaLink="false">http://www.htmlist.com/?p=613</guid>
		<description><![CDATA[Email newsletters for retailers do well to offer frequency controls, or risk driving their best customers insane flooding their inboxes.]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-614 alignright" title="hd_email" src="http://www.htmlist.com/wordpress/wp-content/uploads/2010/08/hd_email.png" alt="" width="213" height="182" /> I recently bought a new house and found myself subscribed to West Elm, Crate and Barrel, and CB2&#8242;s email newsletters as a result. They offer some really good deals, showcase new and fun things for around the house, and they&#8217;re nice and pretty to look at. But these guys brutally violate the tenet of &#8220;not more than once a week, and even twice a month is pushing it&#8221; in the newsletter department, as their default behavior.</p>
<p>I get emailed sometimes as much as three times per week by Crate and Barrel. This is simply <em>too much</em>. The problem is, it&#8217;s all or nothing. While I may want to see when they announce new seasonal items or great upcoming sales, I can either turn it all off, or get barraged with an absurd amount of mail that drives me nuts.</p>
<p>The solution to this is to allow users to choose their newsletter frequency. Harry &amp; David, another frequent emailer, wised up to this and offers four options:</p>
<ul>
<li>&#8220;Keep my emails coming, I want to make sure I receive your best offers&#8221;</li>
<li>&#8220;Send me an email once a week&#8221;</li>
<li>&#8220;Send me an email once every two weeks, plus holiday reminders&#8221;</li>
<li>&#8220;Send me an email once each month, plus holiday reminders&#8221;</li>
</ul>
<p>Brilliant. Since I&#8217;m not dying to be tempted by fresh and delicious pears four times a week, I chose the &#8220;once a month, plus holidays&#8221; option. I still see when new products are in season, and they warn me of upcoming sales, but I&#8217;m not driven to insanity, nor do I start to get frustrated with the brand because our email relationship is now on my terms.</p>
<p>Implementing variable frequency email newsletters, while sounding pretty simple, can be a bit complicated. An organization needs to determine if they want to tailor the less frequent emails differently so that users who are on the frequent list don&#8217;t receive the same email as users on the monthly list, or if they simply want to ratchet down the frequency. Typically, one would apply a simple hierarchy: the monthly email is the same for everyone, the bi-weekly is likewise, and people see the emails they&#8217;ve requested. If a weekly lines up with that month&#8217;s monthly, they&#8217;ll get that message, instead of a separate double.</p>
<p>I know that interactions and brand engagements like this rely on lots of &#8220;touches&#8221; to keep people thinking of you and to encourage repeat sales, but I really wonder about diminishing marginal returns. At the point that I&#8217;m receiving 10 emails from a company a month, how many more purchases can I reasonably be expected to make, versus  sending me 5 emails a month? My personal feeling is that you seriously risk annoying your subscribers without making it back in increased purchases by polluting their inboxes and worse, conscribing yourself into &#8220;automatically delete&#8221; mode for the customer—since all they see is noise, they don&#8217;t even take the time to look inside anymore. When your emails are farther and fewer in between, and a good deal more substantial, your open rates increase and your conversion rates are likely to do the same&#8230; but even if they don&#8217;t, you won&#8217;t be risking damaging your brand, even on a subconscious level, with your best customers.</p>
<p>And your newsletter subscribers ARE some of your best customers—they&#8217;ve volunteered to allow you to spam them on a regular basis, for heaven&#8217;s sake. They trust that you&#8217;ll deliver value and deals and reasons to keep opening their messages. Don&#8217;t abuse that trust, and instead, let them set the boundaries so that you don&#8217;t unwittingly do more harm than good.</p>
<img src="http://www.htmlist.com/wordpress/?ak_action=api_record_view&id=613&type=feed" alt="" />
<p><a href="http://feedads.g.doubleclick.net/~a/wr9fthJnGfP4bjYsefo4iiW2U2Y/0/da"><img src="http://feedads.g.doubleclick.net/~a/wr9fthJnGfP4bjYsefo4iiW2U2Y/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/wr9fthJnGfP4bjYsefo4iiW2U2Y/1/da"><img src="http://feedads.g.doubleclick.net/~a/wr9fthJnGfP4bjYsefo4iiW2U2Y/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/HTMList/~4/A5ZKWhN8drM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.htmlist.com/rants/newsletter-frequency-let-users-decide/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.htmlist.com/rants/newsletter-frequency-let-users-decide/</feedburner:origLink></item>
		<item>
		<title>Amazon S3 Versioning, Multi-Factor Authentication Now Available</title>
		<link>http://feedproxy.google.com/~r/HTMList/~3/8QcDpGLQsHM/</link>
		<comments>http://www.htmlist.com/cool-stuff/amazon-s3-versioning-and-multi-factor-authentication-now-available/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 17:00:00 +0000</pubDate>
		<dc:creator>Chris Cardinal</dc:creator>
				<category><![CDATA[Cool Stuff]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[amazon aws]]></category>
		<category><![CDATA[amazon s3]]></category>
		<category><![CDATA[deletions]]></category>
		<category><![CDATA[mfa]]></category>
		<category><![CDATA[versioning]]></category>

		<guid isPermaLink="false">http://www.htmlist.com/?p=579</guid>
		<description><![CDATA[Amazon reveals their newest addition to their S3 service: Versioning and multi-factor authentication.]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-580" title="MFA Fob" src="http://www.htmlist.com/wordpress/wp-content/uploads/2010/02/mfa.jpg" alt="" width="160" height="120" />Continuing their trend of releasing substantial features and additional services in their web services portfolio on a regular basis, Amazon announced this week the availability of versioning and multi-factor authentication across their Simple Storage Service (S3) property.</p>
<p><strong>How S3 Versioning Works</strong><br />
Versioning is a critical feature many developers had requested as data stored on S3, while maintained in triplicate across the S3 file-system automatically, is still vulnerable to sweeping delete operations by developers, errant scripts, or other causes. Moreover, developers had to manually version changing files if they wanted to preserve the ability to roll-back to an earlier revision or undo a &#8220;delete&#8221;. In any event, a lot of custom code had to be created to replicate these behaviors, and most solutions weren&#8217;t particularly graceful.</p>
<p><span id="more-579"></span></p>
<p>Versioning is <a href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/">easy to enable</a> and brilliant for Amazon: make a simple API call to enable versioning for an entire bucket and all changes to the files within that bucket will preserve versions. Moreover, deletions of files through the typical <code>DELETE</code> API call will simply create a delete marker, making the file unavailable for all intents and purposes, but preserving its presence and all of its versions in the S3 filesystem, until its permanent deletion is called for. It&#8217;s brilliant for Amazon because you pay the additional storage fees for each version and for each &#8220;deleted&#8221; file that hasn&#8217;t been permanently destroyed.</p>
<p>This means that versioning can be easily enabled on any existing S3 implementation with out breaking compatibility with existing code. Naturally, developers will need to rewrite their delete calls to make use of the version delete options, but for an application with little-to-no deletions, this is a feature implemented with a single API call.</p>
<p>Amazon also introduced Multi-Factor Authentication. MFA works with security code-generating key fobs that act as a physical token one must have in order to perform an action. In this case, if you enable MFA, you need the token to log in and manage your AWS account, and you can also optionally require the token to commit a permanent deletion of a file version. For the uninitiated, it&#8217;s considered multi-factor as you need two types of authentication to login or make deletes on your account. (Your AWS username and password for account management and your AWS public/private key for API calls each make up the other half of the multi-factor equation with the MFA code.)</p>
<p><strong>The S3 Trash Bin</strong><br />
Using MFA, it becomes possible to create a highly robust and secure safety net that prevents the wholesale deletion of an S3 account&#8217;s contents without first enforcing an additional review step. After enabling versioning and MFA-Delete mode for a bucket, a developer&#8217;s application will continue to function to the end-user as expected. This means very little rewriting of code needs to be performed to get these features up and running. A simple trash bin script could then be created which would identify all files whose current version is a delete marker, and present them to an admin. Since permanent deletions require the MFA code to be appended to the API call, only the individual with physical access to the code (which recycles every 30 seconds) would be able to commit the delete operations necessary. After reviewing the files queued for permanent deletion, they&#8217;d enter the code and the script would be sent off to the races.</p>
<p>Naturally, this still leaves some room for error: the script that commits the permanent deletes would need to be scrutinized to ensure that it itself is bulletproof, but beyond that, this should protect against nearly all accidental deletions, and establish a command and control hierarchy for an organization. It&#8217;s important to reduce the sheer number of individuals who have complete deletion privileges for myriad reasons, and this helps accomplish that. The MFA key fob is available for all of $13 and you&#8217;re off to the races. You simply input your serial number on the AWS site, and Amazon&#8217;s servers knows what the code it&#8217;s generated should be based on the time and a seed that&#8217;s private to them.</p>
<p><a href="http://aws.amazon.com/mfa/">More on Amazon AWS Multi-Factor Authentication</a><br />
<a href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/Versioning.html">S3 Versioning</a> | Amazon Developer&#8217;s Guide</p>
<img src="http://www.htmlist.com/wordpress/?ak_action=api_record_view&id=579&type=feed" alt="" />
<p><a href="http://feedads.g.doubleclick.net/~a/6GlZB1Xn48zIQzrJB8wHdVDCfg4/0/da"><img src="http://feedads.g.doubleclick.net/~a/6GlZB1Xn48zIQzrJB8wHdVDCfg4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/6GlZB1Xn48zIQzrJB8wHdVDCfg4/1/da"><img src="http://feedads.g.doubleclick.net/~a/6GlZB1Xn48zIQzrJB8wHdVDCfg4/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/HTMList/~4/8QcDpGLQsHM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.htmlist.com/cool-stuff/amazon-s3-versioning-and-multi-factor-authentication-now-available/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.htmlist.com/cool-stuff/amazon-s3-versioning-and-multi-factor-authentication-now-available/</feedburner:origLink></item>
		<item>
		<title>Extending PHP 5.3 Closures with Serialization and Reflection</title>
		<link>http://feedproxy.google.com/~r/HTMList/~3/wNdIG5J-IOE/</link>
		<comments>http://www.htmlist.com/development/extending-php-5-3-closures-with-serialization-and-reflection/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 22:32:57 +0000</pubDate>
		<dc:creator>Jeremy Lindblom</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[classes]]></category>
		<category><![CDATA[closures]]></category>
		<category><![CDATA[magic methods]]></category>
		<category><![CDATA[methods]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[reflection]]></category>
		<category><![CDATA[serialization]]></category>

		<guid isPermaLink="false">http://www.htmlist.com/?p=551</guid>
		<description><![CDATA[Our developer examines Closures in PHP 5.3]]></description>
			<content:encoded><![CDATA[<p>PHP 5.3 has brought with it some powerful and much-needed features like <a href="http://php.net/manual/en/language.oop5.late-static-bindings.php">late static bindings</a>, <a href="http://us3.php.net/manual/en/language.namespaces.rationale.php">namespaces</a>, and closures (also referred to as anonymous functions and lambda functions). Anyone who is experienced with JavaScript or who has worked with programming languages like Scheme or Lisp should realize the value that anonymous functions can bring to PHP. The <a title="PHP Closures (Anonymous Functions)" href="http://www.php.net/manual/en/functions.anonymous.php">PHP Manual explains closures</a> like this:</p>
<blockquote><p>Anonymous functions, also known as closures, allow the creation of functions which have no specified name. They are most useful as the value of callback parameters, but they have many other uses. Closures can also be used as the values of variables; PHP automatically converts such expressions into instances of the Closure internal class.</p></blockquote>
<p>PHP has very few <a title="PHP predefined classes" href="http://php.net/manual/en/reserved.classes.php">predefined classes</a> that are part of the core language, so naturally I was intrigued by the Closure class. The PHP Manual has this to say about the class:</p>
<blockquote><p>The predefined final class Closure was introduced in PHP 5.3.0. It is used for internal implementation of anonymous functions. The class has a constructor forbidding the manual creation of the object (issues <code>E_RECOVERABLE_ERROR</code>) and the <code>__invoke()</code> method with the calling magic.</p></blockquote>
<p>The <a href="http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.invoke">invoke magic method</a> is also a new feature in PHP 5.3. It is called when an object is used in the context of a function (e.g. <code>$object($parameter);</code>). Since Closure objects will be used like functions, this is a critical feature of the Closure object. The Closure class may be perfectly equipped to act like an anonymous function, but it does not provide any extra utility beyond that. A <code>var_dump()</code> of a closure will reveal the functions parameters, but there is no way to get any other information about the Closure (like the actual code of the function). Trying to serialize the Closure throws an Exception and <code>json_encode()</code> just returns an empty JSON string. To make matters worse, the Closure class is <a href="http://us.php.net/manual/en/language.oop5.final.php">final</a>, so there is no way to extend it.</p>
<p>That simply wasn&#8217;t going to cut it for me. I wanted to make my own Closure class that was at least able to do the following: <span id="more-551"></span></p>
<ol>
<li>Invoke the Closure (with <code>__invoke()</code>) just like the PHP Closure class</li>
<li>Retrieve the actual code of the Closure</li>
<li>Retrieve detailed data about the Closure&#8217;s parameters</li>
<li>Retrieve the names and values of any variables inherited from the Closure&#8217;s parent&#8217;s scope (with the <code>use</code> construct)</li>
<li>Serialize and unserialize the Closure</li>
</ol>
<p>I decided to play around with the <a href="http://php.net/manual/en/book.reflection.php">Reflection API</a> to see what kind of information I could get from the Closure. A Closure is a function, so using the <a href="http://us.php.net/manual/en/class.reflectionfunction.php">ReflectionFunction class</a> provides the same information about Closures as it does about any other functions. PHP 5.3 also added the <code>isClosure()</code> method to the ReflectionFunction (in case you weren&#8217;t convinced that reflection would be helpful). After some tinkering, it became apparent that I would be able to accomplish all of my desires. I will walk you through the construction of my &#8220;SuperClosure&#8221; class and explain how the creative use of Reflection allows us to find ways around the problems normally blocking the ability to have my desired features.</p>
<h2 id="toc-1-grant-the-ability-to-invoke-the-closure">1. Grant the ability to invoke the Closure</h2>
<p>The first goal was to create the basic SuperClosure class that both encapsulates and allows invocation of the Closure. To do this I wrote a simple class with a constructor and the magic <code>__invoke()</code> method. I also included an accessor method (getter) for the actual Closure. In the constructor I created an instance of the ReflectionFunction class and stored it as a class member that helped allow invocation of the closure with a variable number of arguments. It also helped me accomplish other things later. The following code shows the basic class upon which I will be building. The complete will be shown at the end of the article.</p>
<pre class="brush: php">class SuperClosure {

	protected $closure = NULL;
	protected $reflection = NULL;

	public function __construct($function)
	{
		if ( ! $function instanceOf Closure)
			throw new InvalidArgumentException();

		$this-&gt;closure = $function;
		$this-&gt;reflection = new ReflectionFunction($function);
	}

	public function __invoke()
	{
		$args = func_get_args();
		return $this-&gt;reflection-&gt;invokeArgs($args);
	}

	public function getClosure()
	{
		return $this-&gt;closure;
	}
}</pre>
<p>The <code>__invoke()</code> method allows the SuperClosure object to be used exactly as if it was a Closure object. I had to recreate this functionality for the SuperClosure class since I was not able to extend the Closure to begin with. In order to pass arguments through to the real Closure, I used a combination of the <a href="http://php.net/manual/en/function.func-get-args.php"><code>func_get_args()</code></a> function and the <code>invokeArgs()</code> method of ReflectionFunction to ensure that any variable number of arguments could be used. I could have also used <code>call_user_func_array()</code> function, but I prefer Reflection, and since I already had an instance of the ReflectionFunction, the <code>invokeArgs()</code> method seemed like a better choice.</p>
<h2 id="toc-2-retrieve-the-actual-code-of-the-function">2. Retrieve the actual code of the function</h2>
<p>Secondly, I added code that allowed the SuperClosure class to find and store the actual code defining the closure. This feature is actually the key to doing the serialization later and is the most complicated part of the program. To accomplish this portion of the program, I used the instance of ReflectionFunction from Step 1 and the <a href="http://php.net/manual/en/class.splfileobject.php">SplFileObject</a> class, an SPL class which provides a nice object-oriented interface for dealing with files. The <code>getFileName()</code>, <code>getStartLine()</code>, and <code>getEndLine()</code> methods of the ReflectionFunction class allowed me to retrieve all the information I needed to find the source code of the Closure function. Using the SplFileObject to open and read from the source file and in combination with some string manipulation, I was able to obtain the closure&#8217;s source code. The following code shows the protected <code>_fetchCode()</code> method used to parse the closure&#8217;s code out of its source file:</p>
<pre class="brush: php">protected function _fetchCode()
{
	// Open file and seek to the first line of the closure
	$file = new SplFileObject($this-&gt;reflection-&gt;getFileName());
	$file-&gt;seek($this-&gt;reflection-&gt;getStartLine()-1);

	// Retrieve all of the lines that contain code for the closure
	$code = &#039;&#039;;
	while ($file-&gt;key() &lt; $this-&gt;reflection-&gt;getEndLine())
	{
		$code .= $file-&gt;current();
		$file-&gt;next();
	}

	// Only keep the code defining that closure
	$begin = strpos($code, &#039;function&#039;);
	$end = strrpos($code, &#039;}&#039;);
	$code = substr($code, $begin, $end - $begin + 1);

	return $code;
}</pre>
<p>The only limitations with the current version of this function are that you cannot have multiple closures on a single line and you cannot use the word &#8220;function&#8221; anywhere besides the actual closure&#8217;s declaration.</p>
<h2 id="toc-3-retrieve-detailed-data-about-the-closures-parameters">3. Retrieve detailed data about the Closure&#8217;s parameters</h2>
<p>Retrieving information about the closure&#8217;s parameters was as simple as adding a method that simply returns the result of the <code>getParameters()</code> method the SuperClosure&#8217;s instance of ReflectionFunction. That&#8217;s all. The <code>getParameters()</code> method returns ReflectionParameter objects which have several methods for getting information about the parameters including their names, values, default values, and more.</p>
<h2 id="toc-4-retrieve-the-names-and-values-of-any-variables-inherited-from-the-closures-parents-scope">4. Retrieve the names and values of any variables inherited from the Closure&#8217;s parent&#8217;s scope</h2>
<p>One of the biggest problems I had was retrieving the names and values of the variables added to the Closure&#8217;s scope with the <code>use</code> construct. There isn&#8217;t a documented way of doing this as far as I know, but I was able to figure out a way to do it after playing around some more with the ReflectionFunction class (it is just so helpful). These variables are actually included in the results of the <code>getStaticVariables()</code> method. If the closure declares any variables with the <code>static</code> keyword, these will also be included in the results. To get around this I added the <code>_fetchUsedVariables()</code> method that uses a combination of the <code>getStaticVariables()</code> method and some string manipulation of the Closure&#8217;s code (from Step 2) to find only the variables that were inherited from the parent&#8217;s scope. The following code shows the <code>_fetchUsedVariables()</code> method:</p>
<pre class="brush: php">protected function _fetchUsedVariables()
{
	// Make sure the use construct is actually used
	$use_index = stripos($this-&gt;code, &#039;use&#039;);
	if ( ! $use_index)
		return array();

	// Get the names of the variables inside the use statement
	$begin = strpos($this-&gt;code, &#039;(&#039;, $use_index) + 1;
	$end = strpos($this-&gt;code, &#039;)&#039;, $begin);
	$vars = explode(&#039;,&#039;, substr($this-&gt;code, $begin, $end - $begin));

	// Get the static variables of the function via reflection
	$static_vars = $this-&gt;reflection-&gt;getStaticVariables();

	// Only keep the variables that appeared in both sets
	$used_vars = array();
	foreach ($vars as $var)
	{
		$var = trim($var, &#039; $&amp;amp;&#039;);
		$used_vars[$var] = $static_vars[$var];
	}

	return $used_vars;
}</pre>
<h2 id="toc-5-grant-the-ability-to-serialize-and-unserialize-the-closure">5. Grant the ability to serialize and unserialize the Closure</h2>
<p>Finally, I implemented the serialization capabilities. Since an actual closure object cannot be serialized (it gives a fatal error), I had to be creative to come up with a way to do my own serialization. The code I wrote for Step 2 and Step 4 made this possible. The <a href="http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.sleep">sleep magic method</a> allows you to hook into the serialization process, so I used this method to prepare my SuperClosure class for serialization. In order for my class to be serialized, I needed to first stop the Closure object and the ReflectionFunction object representing the Closure from being serialized. The <code>__sleep()</code> method should return an array of the class members you are serializing, so I simply left those variables out of the list. Because I was serializing the Closure&#8217;s code and static variables, it made possible in the <code>__wakeup()</code> magic method to recreate the Closure object using the code. To do this I had to use the <code>extract()</code> function on my array of used variables to import them back into the scope. Then I performed an <code>eval()</code> operation on the Closure&#8217;s code in order to recreate the Closure. <code>eval()</code> is always a risky operation, but in this case it makes sense. If you are planning to use this code for any of your own projects, I urge you to take precautions.  The following code shows the complete SuperClosure class with the additions of the <code>__sleep(</code>) and <code>__wakeup()</code> methods.</p>
<pre class="brush: php">class SuperClosure {

	protected $closure = NULL;
	protected $reflection = NULL;
	protected $code = NULL;
	protected $used_variables = array();

	public function __construct($function)
	{
		if ( ! $function instanceOf Closure)
			throw new InvalidArgumentException();

		$this-&gt;closure = $function;
		$this-&gt;reflection = new ReflectionFunction($function);
		$this-&gt;code = $this-&gt;_fetchCode();
		$this-&gt;used_variables = $this-&gt;_fetchUsedVariables();
	}

	public function __invoke()
	{
		$args = func_get_args();
		return $this-&gt;reflection-&gt;invokeArgs($args);
	}

	public function getClosure()
	{
		return $this-&gt;closure;
	}

	protected function _fetchCode()
	{
		// Open file and seek to the first line of the closure
		$file = new SplFileObject($this-&gt;reflection-&gt;getFileName());
		$file-&gt;seek($this-&gt;reflection-&gt;getStartLine()-1);

		// Retrieve all of the lines that contain code for the closure
		$code = &#039;&#039;;
		while ($file-&gt;key() &lt; $this-&gt;reflection-&gt;getEndLine())
		{
			$code .= $file-&gt;current();
			$file-&gt;next();
		}

		// Only keep the code defining that closure
		$begin = strpos($code, &#039;function&#039;);
		$end = strrpos($code, &#039;}&#039;);
		$code = substr($code, $begin, $end - $begin + 1);

		return $code;
	}

	public function getCode()
	{
		return $this-&gt;code;
	}

	public function getParameters()
	{
		return $this-&gt;reflection-&gt;getParameters();
	}

	protected function _fetchUsedVariables()
	{
		// Make sure the use construct is actually used
		$use_index = stripos($this-&gt;code, &#039;use&#039;);
		if ( ! $use_index)
			return array();

		// Get the names of the variables inside the use statement
		$begin = strpos($this-&gt;code, &#039;(&#039;, $use_index) + 1;
		$end = strpos($this-&gt;code, &#039;)&#039;, $begin);
		$vars = explode(&#039;,&#039;, substr($this-&gt;code, $begin, $end - $begin));

		// Get the static variables of the function via reflection
		$static_vars = $this-&gt;reflection-&gt;getStaticVariables();

		// Only keep the variables that appeared in both sets
		$used_vars = array();
		foreach ($vars as $var)
		{
			$var = trim($var, &#039; $&amp;amp;&#039;);
			$used_vars[$var] = $static_vars[$var];
		}

		return $used_vars;
	}

	public function getUsedVariables()
	{
		return $this-&gt;used_variables;
	}

	public function __sleep()
	{
		return array(&#039;code&#039;, &#039;used_variables&#039;);
	}

	public function __wakeup()
	{
		extract($this-&gt;used_variables);

		eval(&#039;$_function = &#039;.$this-&gt;code.&#039;;&#039;);
		if (isset($_function) AND $_function instanceOf Closure)
		{
			$this-&gt;closure = $_function;
			$this-&gt;reflection = new ReflectionFunction($_function);
		}
		else
			throw new Exception();
	}
}</pre>
<h2 id="toc-conclusion">Conclusion</h2>
<p>With some cleverness and reflection, I was able to create the SuperClosure class and extend the Closure&#8217;s normal capabilities. Although my class does not enhance the typical use of a PHP Closure it does make it possible to serialize and transport a closure and provides an interface for examining the parameters and inherited variables. This means that we can do:</p>
<pre class="brush: php">$closure = new SuperClosure(
	function($num1, $num2) {return $num1 + $num2;}
);
$serialized_closure = serialize($closure);
$unserialized_closure = unserialize($serialized_closure);
echo $unserialized_closure(1, 5);
</pre>
<p>without worrying about errors. Also, it would technically be possible to send closures through a remote service.</p>
<p>From what I have read in the PHP Manual, this class may have to be changed in the future. The Manual states this regarding anonymous functions:</p>
<blockquote><p>Anonymous functions are currently implemented using the Closure class. This is an implementation detail and should not be relied upon.</p></blockquote>
<p>So according to this, future versions of PHP might implement closures differently, and my class would have to be rewritten.</p>
<p>If you would like a copy of the code from this article (and an example of its use) you can find it on <a href="http://github.com/jeremeamia/super_closure">my Github account</a>.</p>
<img src="http://www.htmlist.com/wordpress/?ak_action=api_record_view&id=551&type=feed" alt="" />
<p><a href="http://feedads.g.doubleclick.net/~a/5W0n00DI6FbWZptGNMU0MUCUzdQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/5W0n00DI6FbWZptGNMU0MUCUzdQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/5W0n00DI6FbWZptGNMU0MUCUzdQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/5W0n00DI6FbWZptGNMU0MUCUzdQ/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/HTMList/~4/wNdIG5J-IOE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.htmlist.com/development/extending-php-5-3-closures-with-serialization-and-reflection/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		<feedburner:origLink>http://www.htmlist.com/development/extending-php-5-3-closures-with-serialization-and-reflection/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 1.354 seconds. --><!-- Cached page generated by WP-Super-Cache on 2012-02-02 00:45:53 -->

