Singlebrook Technology Singlebrook Technology Blog Posts http://singlebrook.com/blog Heartbleed Bug Recommendations <p>Most of you have probably already heard of the "<a href="http://heartbleed.com/" title="http://heartbleed.com/" target="_blank">Heartbleed Bug</a>", an extremely serious security vulnerability announced this week that affects <a href="https://github.com/musalbas/heartbleed-masstest/blob/master/top1000.txt" title="https://github.com/musalbas/heartbleed-masstest/blob/master/top1000.txt" target="_blank">large swathes of the internet</a>. Incredibly, the bug has been around since&#160;March 2012, and unfortunately it is difficult or impossible to tell if any particular site has been exploited.</p> <p>Here are our recommendations for securing your sites and servers and protecting your data and your users, in order of importance:</span> </p> <ol><li><strong>Assess your current vulnerability.</strong> You can check to see if your site is currently vulnerable with <a href="http://filippo.io/Heartbleed" title="http://filippo.io/Heartbleed" target="_blank">this tool</a>. Note that your server may be vulnerable to attack even if you don't use or require SSL on your site.</li> <li><strong>Ensure that your servers are running a patched version of OpenSSL</strong> (or an older version from before the bug was introduced). We can help you with this, and if you're a Singlebrook customer, chances are good that we've already taken care of this step for you.</li> <li><strong>Install re-issued SSL certificates. </strong>Heartbleed made it possibile to steal servers' private keys, so even if your server is patched, an attacker who has your private key can still decrypt your users' data in transit. Replacing your SSL certificate protects your data in transit for the future. Re-issues of your certificate are typically free with most SSL vendors, but it will take us between 30 minutes and 2 hours to request, approve, and install each new certificate.</li> <li><strong>Reset all user sessions</strong>, requiring that they log in to your site anew.</li> <li><strong>Force all users to reset their passwords.</strong> </li> <li><strong>Notify your users</strong> of the actions you've taken to protect them and their data. Be sure to mention whether your site was vulnerable and for how long. If your web server has SSL, and was using an up-to-date OpenSSL, you've probably been vulnerable for about two years (or the life of the server, whichever is shorter).</li> <li><strong>Reset your passwords</strong>, and use a different password for each account. This is a great time to add a password manager to your toolset, like <a href="https://agilebits.com/onepassword" title="https://agilebits.com/onepassword" target="_blank">1Password</a>&#160;or <a href="https://lastpass.com/" title="https://lastpass.com/" target="_blank">LastPass</a>.</li> </ol> <p>We can help you with these steps. We consider steps 1 and 2 to be absolutely required. Steps 3 and 4 are very strong recommendations if your server was vulnerable to Heartbleed at any time. Steps 5, 6, and 7 are recommended, but optional.</p> Wed, 09 Apr 2014 16:24:00 +0000 http://singlebrook.com/blog/heartbleed-bug-recommendations Singlebrook Annual Report <p><a href="/system/resources/W1siZiIsIjIwMTQvMDQvMDcvMTgvMDMvMTIvODQxL1NpbmdsZWJyb29rXzIwMTNfQW5udWFsX1JlcG9ydF93ZWJfZmluYWwucGRmIl1d/Singlebrook%20-%202013%20Annual%20Report%20-%20web_final.pdf" title="Singlebrook 2013 Annual Report Web Final"><img src="http://d21eqec1zr862y.cloudfront.net/system/images/W1siZiIsIjIwMTQvMDQvMDcvMTgvMDAvNTIvOTc3L3NiX3ZhbHVlcy5wbmciXSxbInAiLCJ0aHVtYiIsIjIyNXgyNTU%2BIl1d" title="Sb Values" alt="Sb Values" rel="225x255" width="191" height="255" class="image-align-left selected_by_wym" style="background-color: transparent;" /></a>&#160;We're happy to share our Annual Report! <a href="/system/resources/W1siZiIsIjIwMTQvMDQvMDcvMTgvMDMvMTIvODQxL1NpbmdsZWJyb29rXzIwMTNfQW5udWFsX1JlcG9ydF93ZWJfZmluYWwucGRmIl1d/Singlebrook%20-%202013%20Annual%20Report%20-%20web_final.pdf" title="Singlebrook 2013 Annual Report Web Final">Download the PDF here.</a> </p> <p>This report serves as an overview of some of the milestones that we hit in 2013, and a look at where we’re headed!</p> Mon, 07 Apr 2014 17:56:00 +0000 http://singlebrook.com/blog/singlebrook-annual-report Food, Fun and Frugal Glass: Our Visit to SXSW <p>By Elisa Miller-Out</p> <p>This spring, our Director of Business Development, Jo Opot and I attended SXSW Edu and SXSW Interactive in Austin. Here are some of the highlights of our trip.</p> <ul><li>The best part of SXSW by far is the community and the opportunity to connect with lots of amazing, brilliant entrepreneurs and educators who have assembled to share their ideas about innovation. We enjoyed meeting folks such as Heather Hiles from <a href="http://pathbrite.com/" title="http://pathbrite.com/" target="_blank" style="background-color: transparent;">Pathbrite</a> and Althea Erickson from <a href="http://etsy.com" title="http://etsy.com" target="_blank" style="background-color: transparent;">Etsy</a>. </li> <li>Spontaneous networking was effortless thanks to the Hilton lobby, break rooms and receptions where we met with&#160;<a href="http://www.learningbird.com/i" title="http://www.learningbird.com/i" target="_blank">Learning Bird</a>, <a href="https://www.simple.com/" title="https://www.simple.com/" target="_blank">Simple</a>,&#160;<a href="http://www.tiu11.org" title="http://www.tiu11.org" target="_blank">Tuscarora Unit 11</a>, <a href="http://www.culturebooster.com/" title="http://www.culturebooster.com/" target="_blank" id="wym-1395847522939">Culture Booster</a> and <a href="http://radafilm.com/" title="http://radafilm.com/" target="_blank">Rada Film Group</a>.</li> <li>We connected with some of our <a href="http://bcorporation.net" title="http://bcorporation.net" target="_blank" style="background-color: transparent;">B Corp</a> friends such as <a href="http://provoc.me/" title="http://provoc.me/" target="_blank" style="background-color: transparent;">Provoc</a>, <a href="https://www.change.org/" title="https://www.change.org/" target="_blank" style="background-color: transparent;">Change.org</a> and <a href="http://mightybytes.com/" title="http://mightybytes.com/" target="_blank" style="background-color: transparent;">MightyBytes</a> at the B Corp Meetup. </li> </ul> <img src="http://sbrefinery.s3.amazonaws.com/2014/03/24/23/35/44/774/B_the_Change_profile_picture.png" title="B The Change Profile Picture" alt="B The Change Profile Picture" rel="225x255" width="180" height="180" /><ul><li>We attended "Women Who Whiskey" and brunch meetups with the <a href="http://techladymafia.com/" title="http://techladymafia.com/" target="_blank" style="background-color: transparent;">Tech Lady Mafia</a>.&#160;</li> <li>I can't stop thinking about those breakfast tacos from <a href="http://torchystacos.com/" title="http://torchystacos.com/" target="_blank" style="background-color: transparent;">Torchy's.</a>&#160;I can't believe I have to wait another year before I can have more of them! </li> <li>Thank you Steven Freidmutter of <a href="http://www.cctec.cornell.edu/" title="http://www.cctec.cornell.edu/" target="_blank">Cornell University</a> for the insiders guide to SXSW and thank you Andrew Schmidt of <a href="http://www.puma.com/" title="http://www.puma.com/" target="_blank">Puma</a>&#160;for introducing us to the best rib joint, Iron Works.&#160;Does anyone know if they can Fedex a ribs platter to the North East?</li> <li>The bar at the <a href="http://www.fourseasons.com/austin/" title="http://www.fourseasons.com/austin/" target="_blank" style="background-color: transparent;">Four Seasons</a> was a great place to meet all our new friends and a good place for celebrity sightings as well.</li> <li>We are still trying to figure out how the manager at <a href="http://www.palmdoor.com/" title="http://www.palmdoor.com/" target="_blank">Palm Door </a>managed to coordinate a simultaneous live Mariachi band, bouncing castle, live blue grass band, a salsa/80s/hip-hop DJ, open bar and late night fajita extravaganza.</li> <li>I stopped by the&#160; <a href="http://dailyjuicecafe.com/" title="http://dailyjuicecafe.com/" target="_blank" style="background-color: transparent;">Daily Juice</a> Cafe to grab a smoothie and some hippy treats. It made me feel a little like I was back home in Ithaca. </li> <li>Google Glass was, of course, the essential wearable tech accessory for most people at the conference. Let's face it--they do look a little funny. I really enjoyed the 3D printed version that Jennifer Turliuk invented called "Frugal Glass".</li> </ul> <p><img src="http://d21eqec1zr862y.cloudfront.net/system/images/W1siZiIsIjIwMTQvMDMvMjUvMTIvMjQvNDkvMjkwL3JvdGF0ZWQuanBnIl0sWyJwIiwidGh1bWIiLCIyMjV4MjU1PiJdXQ" title="Rotated" alt="Rotated" rel="225x255" width="191" height="255" /></p> <ul><li>Some of the tech trends that I noticed in the festival content included: wearable tech, human centered design, the internet of things and smart home devices, open data in government, digital currencies, tech enabled activism and more.</li> <li>The most useful SXSW app was <a href="http://connect.com/" title="http://connect.com/" target="_blank">Connect</a> from Ryan Allis and Anima Sarah Lavoy. Connect maps where your facebook, LinkedIn and other network friends are at any given moment. Exactly what you need at such a large event.</li> <li>It was also fun to also connect with our friends from <a href="http://uvc.org/" title="http://uvc.org/" target="_blank">Upstate Venture Connect</a>, <a href="http://startfast.net/" title="http://startfast.net/">StartFast</a>&#160;and the CNY tech community.</li> <li>I missed <a href="http://studentstartupmadness.com/" title="http://studentstartupmadness.com/" target="_blank">Student Startup Madness</a> this year, but heard that it was a great event. </li> <li>Kudos to Peter Nilsson of Athena and Heather Hiles for remarkably emceeing <a href="http://sxswedu.com/launchedu-emcees-judges" title="http://sxswedu.com/launchedu-emcees-judges" target="_blank">LAUNCHedu</a>&#160;and congrats to the winners.&#160;</li> <li><a href="http://centralathlete.com/downtown/#.UzDEFa1dUhw" title="http://centralathlete.com/downtown/#.UzDEFa1dUhw">Crossfit Central Downtown</a> was just a few blocks from the convention center, so I managed to fit in my Crossfit Games Open workout in between sessions. </li> <li>I love all the eco-friendly bike taxis. That was my favorite way to get around the festival. </li> <li>I'm really excited about the launch of the <a href="http://www.cookbookcreate.com/sxsw" title="http://www.cookbookcreate.com/sxsw" target="_blank">SXSW Cookbook</a> by the awesome founder of Cookbook Create: Anna Curran.</li> <li>Austin food trucks are so much fun. My favorite: <a href="http://thepeachedtortilla.com/" title="http://thepeachedtortilla.com/" target="_blank">The Peached Tortilla</a>. </li> <li>Finally, SXSW wouldn't be complete for me without a trip to Esther's Follies to hear some amazing comics such as <a href="https://en.wikipedia.org/wiki/Kumail_Nanjiani" title="https://en.wikipedia.org/wiki/Kumail_Nanjiani" target="_blank">Kumail Nanjiani</a>&#160;and a night cap at the&#160;<a href="http://www.driskillhotel.com/" title="http://www.driskillhotel.com/" target="_blank">Driskill</a>.</li> </ul> <p>Can't wait till next year's festival!!</p> Mon, 24 Mar 2014 18:41:00 +0000 http://singlebrook.com/blog/food-fun-and-frugal-glass-our-visit-to-sxsw Tech for Change: Drupal for Job Seekers Workshop <p>One way that we live our mission of Tech for Change at Singlebrook is through company-sponsored volunteer time for employees to give back to the communities we serve. A recent T4C initiative was a&#160;free workshop called "Drupal for Job Seekers" that we offered to the&#160;local Ithaca community.&#160;</p> <p>The goal of the Drupal for Job Seekers workshop is to teach workers considering a career move into the tech industry about the possibilities created by learning a technology like Drupal. We held the workshop at&#160;<a href="https://www.facebook.com/pages/Southside-Community-Center/207723956972" title="https://www.facebook.com/pages/Southside-Community-Center/207723956972" target="_blank">Southside Community Center</a>&#160;and&#160;got some&#160;help from Southside and <a href="http://tompkinscountyny.gov/wfny" title="http://tompkinscountyny.gov/wfny" target="_blank">Workforce New York</a>&#160;in spreading the word to attendees, many of whom were unemployed or underemployed.&#160;</p> <p>Here's the pitch we used to recruit attendees:</p> <p><span class="quote"><span class="quote"><span class="caption"><span class="attribution">With minimal computer skills and a little training, you can get a job building websites using Drupal. The Drupal platform is quickly growing in popularity. Local employers, including Cornell and Ithaca College, are hiring Drupal site content managers now! Join Singlebrook developer Lauren Kelly for a free training that explains what Drupal is, how to gain Drupal skills, and how these skills will help get or improve a job. Includes a demo and some hands-on work. </span> </span> </span> </span> </p> <p>10 people attended the workshop, with our talented Drupal developer Lauren Kelly leading the class. True to Murphy's Law, moments before the workshop began, the community center's internet went down. Lauren was able to engage the group with a presentation and follow up discussion on the following Drupal topics:</p> <ul><li>Where it fits in as a job role&#160;</li> <li>How it will help get or improve a job</li> <li>How it fits in as a development tool</li> <li>Prerequisite skills needed</li> <li>How to gain Drupal skills</li> </ul> <p>Unfortunately, the hands-on portion of the workshop (demo/show-and-tell, creating a node and a page) was not possible. We provided a handout for attendees to do some exploration and continued learning at home.&#160;<a href="/system/resources/W1siZiIsIjIwMTQvMDMvMDYvMjAvNTQvMTEvNDY2L0RydXBhbGZvckpvYlNlZWtlcnNSZXNvdXJjZUhhbmRvdXQucGRmIl1d/DrupalforJobSeekersResourceHandout.pdf" title="Drupalfor Job Seekers Resource Handout" style="background-color: transparent;">The handout is available as a PDF here.</a>&#160; </p> <p>Despite the technical difficulties, the group had positive feedback about the workshop. Our hope is that the job seekers in attendance were encouraged to take the next steps in learning Drupal and, ultimately, that they will use their new skills to land a great job.&#160;</p> <p>If you are interested in hosting or organizing a Drupal for Job Seekers workshop with us, please get in touch!</p> <p><img src="http://d21eqec1zr862y.cloudfront.net/system/images/W1siZiIsIjIwMTQvMDMvMDYvMjAvNTMvNDYvNDkyL2RydXBhbF9mb3Jfam9iX3NlZWtlcnNfMTMuMTEuMjEuanBnIl0sWyJwIiwidGh1bWIiLCI0NTB4NDUwPiJdXQ" title="Drupal For Job Seekers 13.11.21" alt="Drupal For Job Seekers 13.11.21" rel="450x450" width="450" height="338" /></p> Thu, 06 Mar 2014 20:29:00 +0000 http://singlebrook.com/blog/tech-for-change-drupal-for-job-seekers-workshop Simplify your JavaScript with Underscore.js <p><em>by Gennie Harris</em> </p> <p>Underscore.js, as described on their <a href="http://underscorejs.org/" title="http://underscorejs.org/" target="_blank">website</a>, is "a utility-belt library for JavaScript that provides a lot of the functional programming support that you would expect in Prototype.js (or Ruby), but without extending any of the built-in JavaScript objects." </p> <p>Simply put, this means that you can drastically transform your arrays, objects, and functions with only a line or three of code, making underscore arguably the single most useful JavaScript library ever written.</p> <h3>What it gives you</h3> <p>Let's say, for example, that you're doing some work on your Joss Whedon fan site, for which you have some data structured along these lines:</p> <pre><code>var jossWhedon = { age: 49, occupations: ["writer", "director", "producer", "composer", "actor"], shows: [ { title: "Dollhouse", femaleLead: true, characters: [ { name: "Echo", role: "doll" }, { name: "Topher", role: "mad scientist" } ] }, { title: "Dr. Horrible's Sing-Along Blog", characters: [ { name: "Billy", role: "mad scientist" }, { name: "Penny", role: "love interest" } ] }, { title: "Buffy the Vampire Slayer", femaleLead: true, characters: [ { name: "Buffy", role: "slayer" }, { name: "Angel", role: "love interest" } ] }, { title: "Firefly", characters: [ { name: "Mal", role: "captain" }, { name: "Kaylee", role: "mechanic" } ] } ] } </code> </pre> <p>How can you easily manipulate this data to sort and display it in the various ways necessary to run a successful site? Underscore provides over 80 functions, which do everything from basic mapping of arrays (<strong>map</strong>, of course) to creating "flexibly-numbered lists of integers" (<strong>range</strong>), to inverting the keys and values of an object (<strong>invert</strong>). Though you may find edge cases in which dozens of these become useful, there are a few that you'll find invaluable time and time again.</p> <h4>Pluck</h4> <p>One of the most convenient of Underscore's functions, <strong>pluck</strong> creates an array of property values. This is excellent for displaying or manipulating subsets of data. Want to see a human-readable list of the shows that Joss Whedon’s worked on, for example? With straight JavaScript, we’d probably do something like this:</p> <pre><code>jossWhedon.shows.map(function(show) { return show.title; }); =&gt; ["Dollhouse", "Dr. Horrible's Sing-Along Blog", "Buffy the Vampire Slayer", "Firefly"] </code> </pre> <p>This isn’t so bad, but <strong>pluck</strong> allows us to simplify it even further:</p> <pre><code>_.pluck(jossWhedon.shows, "title"); =&gt; ["Dollhouse", "Dr. Horrible's Sing-Along Blog", "Buffy the Vampire Slayer", "Firefly"] </code> </pre> <h4>FindWhere</h4> <p><strong>findWhere</strong> returns the first value in a list that matches all of the listed key-value pairs. This can be useful for returning an object based on a dynamic value such as user input. So if we wanted to find a show based on its title, we would something like this without Underscore:</p> <pre><code>for (var i = 0; i &lt; jossWhedon.shows.length; i++) { if (jossWhedon.shows[i].title === "Firefly") { var show = jossWhedon.shows[i]; } } =&gt; {title: "Firefly", characters: Array[2]} </code> </pre> <p>Or we could shorten this into a single line of code using Underscore’s <strong>findWhere</strong>:</p> <pre><code>var show = _.findWhere(jossWhedon.shows, {title: “Firefly”}); =&gt; {title: "Firefly", characters: Array[2]} </code> </pre> <h4>Reduce</h4> <p><strong>Reduce</strong> condenses a list of values into a single value, just like JavaScript’s native <strong>reduce</strong> method (in fact, Underscore delegates to native methods when available). We can use it here to give us one array containing all of Whedon’s characters. It doesn’t look too different from non-Underscore <strong>reduce</strong>:</p> <pre><code>_.reduce(jossWhedon.shows, function(memo, show) { return memo.concat(show.characters); }, []); =&gt;[{ name: "Echo", role: "doll" }, { name: "Topher", ... }, { name: "Billy", ...}, ...] </code> </pre> <p>Why bother using Underscore’s methods where there are native equivalents? Aside from maintaining consistency across your code, you also gain the benefit of backwards compatibility with older browsers that may not support these native methods.</p> <h3>What you can do with it</h3> <p>Underscore's functions are useful enough on their own, but it's really when you chain them that you can start doing some powerful stuff.</p> <h4>Whedon’s Heroines</h4> <p>Let’s say you want to generate an array of all shows with female leads. Without Underscore, you’d end up with something that looked like this:</p> <pre><code>jossWhedon.shows.filter(function(show) { return show.femaleLead; }).map(function(show) { return show.title; }); =&gt; ["Dollhouse", "Buffy the Vampire Slayer"] </code> </pre> <p>This works, but it’s a little clunky. We can slim it down with Underscore:</p> <pre><code>_.pluck(_.filter(jossWhedon.shows, function(show) { return show.femaleLead; }), "title"); =&gt; ["Dollhouse", "Buffy the Vampire Slayer"] </code> </pre> <p>Here we use <strong>filter</strong> to find the shows that have a female lead, and then <strong>pluck</strong> to extract their titles.</p> <h4>Counting Characters</h4> <p>What if you want to show some statistics on character distributions in the Whedonverse? How many love interests are there, for example, or how many slayers? With straight JS you might do something along these lines:</p> <pre><code>jossWhedon.shows.reduce(function(memo, show) { show.characters.forEach(function(character) { (!memo[character.role]) ? memo[character.role] = 1 : memo[character.role]++; }); return memo; }, {}); =&gt; {doll: 1, mad scientist: 2, love interest: 2, slayer: 1, captain: 1, mechanic: 1} </code> </pre> <p>Instead of using <strong>reduce</strong> to create our object, manually cataloging each role and then counting additional instances, we can use a single line of Underscore to achieve the same thing:</p> <pre><code>_.countBy(_.flatten(_.pluck(jossWhedon.shows, "characters")), "role"); =&gt; {doll: 1, mad scientist: 2, love interest: 2, slayer: 1, captain: 1, mechanic: 1} </code> </pre> <p>We use <strong>pluck</strong> to pull the character arrays from each show and <strong>flatten</strong> to condense them into a single array. Then we can use Underscore’s <strong>countBy</strong> method to catalog the instances of each role.</p> <h4>Mad Scientists? Muahaha!</h4> <p>Finally, let's catalog all the mad scientists that Whedon features in his shows. If we want a single object with each pertinent show as a key and its mad scientist as its value, our JavaScript might get a little unwieldy:</p> <pre><code>var isMadScientist = function(character) { return character.role === "mad scientist" }; jossWhedon.shows.reduce(function(memo, show) { if (show.characters.some(isMadScientist)) { show.characters.forEach(function(character) { if (isMadScientist(character)) { memo[show.title] = character.name; } }); } return memo; }, {}); =&gt; Object {Dollhouse: "Topher", Dr. Horrible's Sing-Along Blog: "Billy"} </code> </pre> <p>We can achieve the same results with very similar methods in Underscore, but the resulting code ends up a lot cleaner:</p> <pre><code>var isMadScientist = function(character) { return character.role === "mad scientist" }; _.reduce(jossWhedon.shows, function(memo, show) { if (_.some(show.characters, isMadScientist)) { memo[show.title] = _.detect(show.characters, isMadScientist).name; } return memo; }, {}); =&gt; Object {Dollhouse: "Topher", Dr. Horrible's Sing-Along Blog: "Billy"} </code> </pre> <p>Here we’re using <strong>reduce</strong> again to condense our shows into a single mad-scientist-riddled object. For each show, we’re first checking if it has a mad scientist using <strong>some</strong> and our <strong>isMadScientist</strong> function. For each show that does indeed contain an evil genius, we find that character using <strong>detect</strong>, and then use their name as the value for the appropriate attribute (the show’s title) on our memo object.</p> <h3>More on Underscore</h3> <p>It’s easy to see even in these limited examples just how useful Underscore can be, which may explain why it’s used on sites like Reddit, Huffington Post, and LinkedIn, and has been included in Drupal 8 Core. Want to learn more? <a href="http://underscorejs.org/" title="http://underscorejs.org/" target="_blank">Underscore’s website</a> is an excellent resource, and check out Michael Fogus’ <a href="http://blog.fogus.me/2013/03/20/fun-js/" title="http://blog.fogus.me/2013/03/20/fun-js/" target="_blank">Functional JavaScript</a>, which uses Underscore to “to highlight and explain functional programming techniques.”</p> <p>If you have any questions on the examples here, if you’ve used Underscore to simplify any of your projects, or even if you're just a big fan of Buffy the Vampire Slayer, we’d love to hear from you in the comments!</p> Mon, 03 Mar 2014 19:10:00 +0000 http://singlebrook.com/blog/simplify-your-javascript-with-underscorejs ReBusiness Chamber Challenge Winners Recognized <p>Singlebrook was named the ReBusiness Chamber Challenge winner! Watch the award acceptance video, courtesy of Moving Box Studios, and check out the press release below!</p> <a href="http://vimeo.com/movingboxstudios/review/84795100/0eb385b623"><img src="http://b.vimeocdn.com/ts/461/810/461810550_960.jpg" style="width:555px;" /></a> <p>(Ithaca, NY) – Two Ithaca-based businesses have been recognized by the Chamber of Commerce and Tompkins County Solid Waste Division for reducing the amount of waste they generate.</p> <p>Under the 2013 ReBusiness Chamber Challenge, businesses and organizations were encouraged to reduce their collective waste footprint by practicing the four R's - Reduce, ReUse, Recycle and ReBuy. The Challenge took place from July to December, with the award winners recognized January 30th at the Chamber of Commerce Annual Dinner and Meeting.</p> <p>Singlebrook Technology is a web programming and designing firm that achieved a 65% waste diversion rate by recycling toner cartridges, electronics and fluorescent tubes; reusing scrap paper and packaging; and making green purchasing decisions. They are also composting!</p> <p>Jamex Incorporated offers quality vending and control products for copiers, network printers and other document imaging equipment. It achieved a 50% waste diversion rate by recycling materials such as toner cartridges, electronics and scrap metal, as well as large amounts of plastic packaging and film. They also reuse material and practice green purchasing techniques.</p> <p>Congratulations to Singlebrook and Jamex for doing their part to help make our community more sustainable! If your business is interested in receiving a free waste assessment and becoming a ReBusiness Partner, contact Tompkins County Solid Waste at (607)273-6632.</p> Thu, 20 Feb 2014 18:50:00 +0000 http://singlebrook.com/blog/rebusiness-chamber-challenge-winners-recognized 9 Expert Tips on Higher Ed Crowdfunding <p><em>by Jo Opot</em> </p> <p>Interview with Freeman White, Co-founder and CEO, Launcht </p> <p>An increasing number of universities and colleges are using crowdfunding platforms to raise donations for everything from their annual fund to student entrepreneurs. However, there is little data, examples, or shared wisdom on how to implement a successful university crowdfunding platform. Unfortunately, many Higher Ed institutions end up re-inventing the wheel or mistakenly adopting best practices meant for entrepreneurs and non-profits that backfire or at the very least fall short of expectations. </p> <p>To address this challenge, I interviewed Freeman White, CEO of Launcht, a white-label crowdfunding platform provider that has supported 15 Higher Ed institutions, including The University of San Diego Business School, Colby College, Central Michigan University and Pace University among others.<br /> <br />Here are 9 tips on Higher Ed crowdfunding from the expert:</p> <h4>Where to begin?</h4> <p>1. <strong>Secure buy-in from all your stakeholders</strong>. You will probably need to engage your in-house tech team, alumni engagement office, office of the president and accounting department, in addition to the campaign leaders. Make sure you get as many of them on board as possible before you begin buying the technology. This will not only translate into a larger group of supporters, but will also allow you to execute the campaign rapidly. For instance, Pace University and Kean University were able to plan and launch in record time primarily because they already had their ducks in a row.</p> <p>2. <strong>Consider starting with a crowdvoting initiative</strong>. Crowdvoting is easier to implement because you do not have to go through the development office and you can use it to gain interest in a subsequent crowdfunding platform. Utah Valley University used crowdvoting for an online competition that selected Utah-based ventures to receive $5,000 grants. Over the campaign’s 30 days, the competing 30 projects had 16,982 unique visitors and collected 9,947 total votes. These impressive results not only won over all the stakeholders, but also made a great case for further crowdsourcing initiatives.</p> <h4>Who to engage?</h4> <p>3. <strong>Don’t build the crowdfunding platform yourself</strong>. Yes, you have a fantastic in-house tech team, but you can easily find cheaper, white-label crowdfunding software that meets your needs. Think easy-to-use, customized and lightweight. This will allow you to maximize your budget by acquiring out-of-the-box technology while using the bulk of the budget to engage your target demographic.</p> <p>4. <strong>Identify the right tech partner</strong>. You want a platform that gives you control of your data, control of your brand image, absolute project approval and direct content approval. In addition, you want all the web traffic that comes in to remain on your university site. It is a tall order, and yes, you can have it all if you opt for a white-label crowdfunding platform instead of the monolithic external crowdfunding sites like Kickstarter and Indiegogo.</p> <h4>What to expect?</h4> <p>5. <strong>Let’s talk numbers</strong>. How much will you raise per donation? The University of Vermont found that the average donation on their crowdfunding platform was $67. Similarly, Launcht has seen the average donation amount to be approximately $50, which means that this will not be the core of a large capital raise. However, it would be a great matching gift program, whereby dramatically increased participation numbers are used to engage larger donors.</p> <p>6. <strong>Know your target demographic and choose a suitable campaign</strong>. The best donor segment attracted by a crowdfunding platform is tech-savvy young alumni. They are also stakeholders you have previously had a difficult time engaging with more traditional strategies like phone calls and email. <em>In fact, University of Arizona noted that 90% of their crowdfunding donors were new donors</em>. You should categorize crowdfunding as a new donor engagement strategy and select campaigns that are easy to understand with immediate results. Make sure you also have an equally savvy post-campaign strategy to keep them involved in the long term.</p> <h4>How to engage?</h4> <p>7. <strong>Get your grassroots team ready</strong>. Crowdfunding is not a “build it and they will come” initiative. The success stories often look effortless, but there is a tremendous amount of behind–the-scenes preparation and execution. Start with educating your campaign leaders on how to use the crowdfunding platform. Make sure you or your campaign leaders secure offline commitments of at least 30% of the campaign goal before the campaign even launches. You have a higher chance of raising your target goal if the campaign appears to have funders from the start.&#160;Once the campaign is running, make sure the campaign leaders continue to promote their progress through local or national PR, blogs, and social media to get the word out and drive even more traffic to your platform.</p> <p>8. <strong>The show and tell</strong>. Suit up your campaign with a TIE (Tangible + Immediate + Evocative) appeal. To elaborate, </p> <ul><li>A tangible campaign is one your target demographic can see, touch or visit. Feel free to showcase the product of the crowdfunding during alumni or homecoming weekend.&#160;</li> <li>As for immediacy, donors expect to see quick results within a few months of their donation.&#160;</li> <li>Evoke an emotional connection with the campaign or campaign leaders. The easiest way to be evocative is with a 1-2 minute video. Campaigns that have a video are more successful that those that don’t, and a homemade video is still better than no video.</li> </ul> <p>9. <strong>Start with showcasing at least 6 campaigns.</strong> Similar to the psychological comfort of seeing a range of food items on a menu even if you order the same dish every time, donors like to see a variety of campaigns taking place. This approach also promotes competition between the various campaigns and increases the number of campaign leaders driving traffic to the site. University of Vermont launched with 8 relatively different campaigns and not only saw very positive results, but also engaged donors through multiple campaigns even if they had arrived at the site for a specific campaign.</p> <p>For more Higher Ed Tech resources please visit our <a href="http://singlebrook.com/work" title="http://singlebrook.com/work" target="_blank">case study page</a> and be in touch if you would like to learn more about how <a href="http://singlebrook.com/" title="http://singlebrook.com/" target="_blank">Singlebrook</a> can address your Higher Ed needs.</p> Tue, 11 Feb 2014 17:16:00 +0000 http://singlebrook.com/blog/9-expert-tips-on-higher-ed-crowdfunding utf8-cleaner gem protects your Rails app <p>TL;DR: Add our <a href="https://github.com/singlebrook/utf8-cleaner" title="https://github.com/singlebrook/utf8-cleaner" target="_blank">utf8-cleaner</a>&#160;Ruby gem to your Rails app and kiss request encoding errors goodbye!</p> <p>Our Rails apps send us <a href="https://github.com/smartinez87/exception_notification" title="https://github.com/smartinez87/exception_notification" target="_blank">error reports by email</a> every time a request results in a <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html" title="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html" target="_blank">500 error</a>. Sometimes these are <a href="/blog/web-developments-dirty-little-secret" title="/blog/web-developments-dirty-little-secret">legitimate bugs</a>, and we can roll out a fix to our code. However, sometimes they're just the result of a misbehaved user agent (browser or search engine bot).</p> <p>Several of our Rails apps, including this site, were reporting errors like "invalid byte sequence in UTF-8". In our apps, this was almost always caused by a parameter in the request URL called "Result" whose value was a pile of <a href="https://en.wikipedia.org/wiki/Percent-encoding" title="https://en.wikipedia.org/wiki/Percent-encoding">URL-encoded</a>, non-<a href="https://en.wikipedia.org/wiki/ASCII" title="https://en.wikipedia.org/wiki/ASCII" target="_blank">ASCII</a> characters. We never figured out where this parameter was coming from, but we could tell that the encoded characters were not valid <a href="https://en.wikipedia.org/wiki/UTF-8" title="https://en.wikipedia.org/wiki/UTF-8" target="_blank">UTF-8</a> characters when we tried to decode them.</p> <p>Rails, helpful framework that it is, does a bunch of work to parse incoming parameters before they get handed to your application code. Unfortunately, it does not provide a built-in mechanism for handling badly-encoded characters. However, there is a very convenient place to plug in code before it gets to Rails, and that is <a href="http://guides.rubyonrails.org/rails_on_rack.html" title="http://guides.rubyonrails.org/rails_on_rack.html" target="_blank">Rack middleware</a>. Middleware was mysterious to me for a while, but it's actually pretty simple conceptually. Rack middleware is a stack of software that processes each incoming request and each outgoing response. It lives between your web server and your framework. Because of where it's located, it's the perfect place to clean up those funky request parameters before Rails can choke on them. </p> <p>Because we were seeing these problems in multiple apps, we wanted to be able to easily share the fix. <a href="https://rubygems.org/" title="https://rubygems.org/" target="_blank">Ruby's gem packaging system</a> was an obvious good fit. We created a <a href="https://github.com/singlebrook/utf8-cleaner" title="https://github.com/singlebrook/utf8-cleaner" target="_blank">gem called utf8-cleaner</a> using the simple <code><a href="http://bundler.io/v1.5/rubygems.html">bundle gem</a> </code>&#160;command.&#160;</p> <p>We built our middleware, using test-driven development to keep our design clean and ensure that we were solving the right problems. We <a href="https://github.com/singlebrook/utf8-cleaner/blob/master/lib/utf8-cleaner/middleware.rb#L23" title="https://github.com/singlebrook/utf8-cleaner/blob/master/lib/utf8-cleaner/middleware.rb#L23" target="_blank">used the String class's encoding methods</a> where possible, but we also had to do some <a href="https://github.com/singlebrook/utf8-cleaner/blob/master/lib/utf8-cleaner/uri_string.rb#L32" title="https://github.com/singlebrook/utf8-cleaner/blob/master/lib/utf8-cleaner/uri_string.rb#L32" target="_blank">more manual processing of the encoded characters</a>&#160;because we were dealing with such malformed input. In the process, we <a href="https://github.com/singlebrook/utf8-cleaner/blob/master/lib/utf8-cleaner/uri_string.rb#L95" title="https://github.com/singlebrook/utf8-cleaner/blob/master/lib/utf8-cleaner/uri_string.rb#L95" target="_blank">learned way more about UTF-8 encoding</a> than we every wanted to!</p> <p>Once the middleware was doing its job, we needed to tie it into Rails. Enter <a href="http://api.rubyonrails.org/classes/Rails/Railtie.html" title="http://api.rubyonrails.org/classes/Rails/Railtie.html" target="_blank">Railties</a>, which lets your code hook into the various places Rails, including the initialization process. <a href="https://github.com/singlebrook/utf8-cleaner/blob/master/lib/utf8-cleaner/railtie.rb" title="https://github.com/singlebrook/utf8-cleaner/blob/master/lib/utf8-cleaner/railtie.rb" target="_blank">Our Railtie</a> simply inserts our middleware at the front of the middleware stack. This ensures that we'll be able to clean up the nasty parameters before they hit any other Ruby code that might choke on them.</p> <p>With the Railtie in place, we tested our new gem locally by <a href="http://bundler.io/v1.5/gemfile.html" title="http://bundler.io/v1.5/gemfile.html" target="_blank">using the <code>:path</code> option in our app's Gemfile</a>. By doing so, we were able to work out any integration issues before we pushed the gem up to <a href="http://rubygems.org" title="http://rubygems.org" target="_blank">rubygems.org</a>&#160;with the beautifully simple <code>rake release</code> command provided by Bundler.</p> <p>Because Rails and Rack provide so many integration points, <a href="https://github.com/singlebrook/utf8-cleaner#utf8cleaner" title="https://github.com/singlebrook/utf8-cleaner#utf8cleaner" target="_blank">using utf8-cleaner is as easy as adding it to your Gemfile and running <code>bundle install</code> </a>. It currently cleans&#160;HTTP_REFERER, PATH_INFO, QUERY_STRING, REQUEST_PATH, REQUEST_URI, and HTTP_COOKIE, but the design should allow it to clean other environment vars (e.g. a POST request body) pretty easily.</p> <p>We'd love to hear your feedback on this gem! It's quieted down our error reports, significantly increasing our signal-to-noise ratio. We hope you'll find it useful!</p> Fri, 07 Feb 2014 00:40:00 +0000 http://singlebrook.com/blog/utf8-cleaner-gem-protects-your-rails-app Modernize Your Drupal Theme <p><em>by Dustin LeBlanc</em> </p> <p>Front-end web development is a hotbed of innovation. The Javascript world is brimming with new frameworks like Backbone, Ember, Angular, Voxel, and Three. There are a lot of exciting technologies to learn to keep our minds busy and skills sharp.</p> <p>Day to day Drupal development in the real world often includes working on a lot of legacy sites. Many of these sites are still running on Drupal 6 and frequently using some legacy themes, developed before the widespread use of CSS superset frameworks like SASS and LESS.</p> <p>Fear not good Drupal themer! You will not be tormented in the world of plain CSS for the rest of your days! With a little help from some RubyGems you can convert your legacy theme to use SCSS with minimal effort as I did for a project I recently inherited. I will show you how in a second; but first, here are some of the reasons I chose to invest the time and energy:</p> <ul> <li>Coding stylesheets in one consistent format across projects helps me code faster.</li> <li>More organized project files help me code faster.</li> <li>The syntax of SCSS feels more like programming, which makes the transition between writing stylesheets, templates, and module files a little more seamless for me (which, you guessed it, makes me code faster :D ).</li> <li>Modular stylesheets using <code>includes</code> help future developers understand the theme more easily.</li> </ul> <p>The big win here is that the time invested to do the conversion will reduce the cost of all future theming work I do on the site. I am laying groundwork for future theming that inevitably needs to be done as this business is dynamically changing and there is already more theming work in the pipeline. If I knew a switch to Drupal 7 were in the immediate future I might hold off for the development of a new theme (Using <a href="https://github.com/singlebrook/drupal_streamline" title="https://github.com/singlebrook/drupal_streamline" target="_blank">Drupal Streamline</a>&#160;to bask in all of my SCSS, Guard, and Live Reload glory).</p> <p>Before we begin; make sure you have Ruby installed and are using the latest versions of RubyGems and Bundler. I personally use rbenv to manage my Ruby versions. The commands here assume a unix style terminal.</p> <p>The first thing we want to do is get to our document root on the command-line:</p> <p>&#160; <code>$ cd mysite</code> </p> <p>Once we are there (wherever "there" is for you), we need to create a Gemfile:</p> <p>&#160; <code>$ touch Gemfile</code> </p> <p>The Gemfile is a manifest of RubyGems used in a project. We will be using two RubyGems in particular, 'sass' and 'compass'. In a future post, hopefully I can tackle retrofitting Guard and Live Reload as well.</p> <p>Open the Gemfile in your favorite text editor (I prefer Sublime) and add the following:</p> [script src="https://gist.github.com/dustinleblanc/30c9d3304e8bf79d813f.js"][/script] <p>Simple as pie. These three lines will tell Bundler where we want to get our Ruby Gems from, and then a list of the two packages we want to include; 'sass' and 'compass'.</p> <p>Close up your text editor and head back to your terminal and input: <code>$ bundle install</code> </p> <p>Your output should look something like:</p> [script src="https://gist.github.com/dustinleblanc/9bab46139d890fbbbc17.js"][/script] <p>Our next step is to turn our attention to our theme files. In a traditional theme, we will have our css files stored in a folder called "css". You may have multiple files stored in this folder, possibly for different outputs such as screen or print. For any files that are partials that render together, typically I combine them all down to a single legacy file. The first thing we will want to do is get into our theme's root directory, usually located somewhere like <code>sites/all/themes/theme_name</code>.</p> <p>We want to create a new folder to hold our scss files (execute from your theme root):</p> <p>&#160; <code>$ mkdir scss</code> </p> <p>Your folder structure may vary. For Singlebrook we typically use a folder structure that lists css, images, js, scss, templates, template.php, and our info file all at our theme root. Next we need to make a new manifest for our scss files:</p> <p>&#160; <code>$ touch scss/style.scss</code> </p> <p>This is our master scss file that will call out our other partials. The first one I typically add is a legacy scss file that contains all of the existing css code, converted to scss. The way you include these files can vary, but the way I have done it is to concatenate them all down to one file called legacy.scss:</p> <p>&#160; <code>$ cat file1.css file2.css file3.css &gt;&gt; scss/_legacy.scss</code> </p> <p>This should concatenate all of your old css into a single <code>_legacy.scss</code> file. Because scss is just a superset of css, you don't have to refactor this code at all; it just works. For now we are going to leave our original css files intact. Things are not fully working yet; we still have some work to do.</p> <p>The above step isn't required. In my case, it simply helped to get all of the existing styles into a single file. This made a clear separation between the old files, coded in plain CSS, and any new files that I created after switching. If there is some existing logical separation in the files that would be best to maintain going forward, it may be best to simply copy each file from the css directory to the scss directory. Then rename them by including a leading underscore and converting the file extension to scss. All of this will depend on the setup of your existing theme. Some themes will include files that need to be separate. </p> <p>Open your <code>style.scss</code> file and the first thing we need to add is our <code>_legacy.scss</code> partial. Notice that the file name contains an underscore at the beginning of the filename. This tells Compass that this is a partial and not to render it to a separate css file when it does our conversion later. This allows us to call this file as a partial into our manifest like so:</p> [script src="https://gist.github.com/dustinleblanc/d858a36c11a6b00dfb26.js"][/script] <p>Notice that I have included a few other partials here too. I am bringing Compass along for the ride so that we can use any of its built-in goodness. You will notice both the <code>_variables.scss</code> file and the <code>_mixins.scss</code> file listed in this manifest as well.&#160;</p> <p>You can already see that I am beginning to break out my files into sensible partials for future development. This is one of my favorite things about SASS (besides the syntax making more sense). I can include these neatly packaged files that <a href="https://en.wikipedia.org/wiki/Don't_repeat_yourself" title="https://en.wikipedia.org/wiki/Don't_repeat_yourself" target="_blank">DRY</a> up my other stylesheets. When handling a specific layout issue for a particular page, I don't want the stylesheet cluttered with all of our vendor prefixes for making a rounded corner or a transparent overlay. All that code gets bundled into a mixin that I then call <code>@include</code> to snatch into my other stylesheet.&#160;</p> <p>On to the next part of making this happen. We need a destination file for all of our scss to be output to (execute from theme root again):</p> <p><code>$ touch css/style.css</code> </p> <p>If you already have a style.css file, you might want to rename it before creating the new file.</p> <p>We now need to tell compass what our input and output files are going to be. Make sure you execute this command from your project root:</p> <p>&#160; <code>$ compass config --css-dir path/to/your/css/directory --sass-dir path/to/your/scss/directory</code> </p> <p>This will create a config directory containing <code>compass.rb</code>, a Ruby file to contain our Compass configuration. You can edit that file for any custom configuration you want, including the format of the output css.</p> <p>All that is left is to point Drupal at our new CSS file in the .info file of our theme:</p> <p>&#160; <code>stylesheets[all][] = css/style.css</code> </p> <p>From our project root we can now call:</p> <p>&#160; <code>$ compass watch</code> </p> <p>We are now using SCSS to write all of our files and letting Compass reload them for us every time we save.</p> <p>Not every project has the immediate budget to upgrade an existing site to Drupal 7. Those sites will still need new features and styling as they continue to age. Just because your theme was developed without SCSS doesn't mean that you can't benefit from the recent advances in front end technology. It is easier than you might think.</p> <p>I am interested in what other types of techniques folks are using to update existing sites and themes. If you have an interesting technique to share, post it in the comments below!</p> Thu, 16 Jan 2014 09:08:00 +0000 http://singlebrook.com/blog/modernize-your-drupal-theme A Conversation With: A serial entrepreneur takes on Ithaca <h3>Singlebrook CEO Elisa Miller-Out was interviewed for Ithaca Journal's "A Conversation With:" series and made the front page of the recent edition!</h3> <p>Read the full article and watch the video interview on <a href="http://www.ithacajournal.com/article/CB/20131213/NEWS01/312130074?utm_source=buffer&amp;utm_campaign=Buffer&amp;utm_content=bufferecb51&amp;utm_medium=twitter&amp;nclick_check=1" title="http://www.ithacajournal.com/article/CB/20131213/NEWS01/312130074?utm_source=buffer&amp;utm_campaign=Buffer&amp;utm_content=bufferecb51&amp;utm_medium=twitter&amp;nclick_check=1" target="_blank">theithacajournal.com</a>.</p> <object id="flashObj" width="480" height="270" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,47,0"><param name="movie" value="http://c.brightcove.com/services/viewer/federated_f9?isVid=1&amp;isUI=1" /><param name="bgcolor" value="#FFFFFF" /><param name="flashVars" value="omnitureAccountID=gpaper140,gntbcstglobal&amp;pageContentCategory=NEWS&amp;pageContentSubcategory=NEWS01&amp;marketName=Ithaca:ithacajournal&amp;revSciSeg=&amp;revSciZip=&amp;revSciAge=&amp;revSciGender=&amp;division=newspaper&amp;SSTSCode=&amp;videoId=2932206070001&amp;playerID=944329334001&amp;playerKey=AQ~~,AAAACNNiDck~,XRgWp-liuX1t7qp__j6q2ky6cK99gjcR&amp;domain=embed&amp;dynamicStreaming=true" /><param name="base" value="http://admin.brightcove.com" /><param name="seamlesstabbing" value="false" /><param name="allowFullScreen" value="true" /><param name="swLiveConnect" value="true" /><param name="allowScriptAccess" value="always" /><embed src="http://c.brightcove.com/services/viewer/federated_f9?isVid=1&amp;isUI=1" flashvars="omnitureAccountID=gpaper140,gntbcstglobal&amp;pageContentCategory=NEWS&amp;pageContentSubcategory=NEWS01&amp;marketName=Ithaca:ithacajournal&amp;revSciSeg=&amp;revSciZip=&amp;revSciAge=&amp;revSciGender=&amp;division=newspaper&amp;SSTSCode=&amp;videoId=2932206070001&amp;playerID=944329334001&amp;playerKey=AQ~~,AAAACNNiDck~,XRgWp-liuX1t7qp__j6q2ky6cK99gjcR&amp;domain=embed&amp;dynamicStreaming=true" width="480" height="270" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" /></object> Thu, 19 Dec 2013 18:54:00 +0000 http://singlebrook.com/blog/a-conversation-with-a-serial-entrepreneur-takes-on-ithaca