<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description>Embedly is your front-end toolkit for building smarter, more beautiful interfaces</description><title>Embedly Blog</title><generator>Tumblr (3.0; @embedly)</generator><link>http://blog.embed.ly/</link><item><title>Build or Buy the API</title><description>&lt;p&gt;&lt;span&gt;Build vs Buy is a classic debate. Do we spend the money on internal resources to build a product or do we just pay someone else to do it for us?&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The common approach is to just compare what it will cost internally vs externally. Two Engineers for 6 months vs X dollars for the product.&lt;/p&gt;
&lt;p&gt;Rather than thinking about the product itself it’s helpful to think of the intangibles that aren’t inherent in the buy, the things that would be difficult to obtain by building the product yourself.&lt;/p&gt;
&lt;p&gt;So what are you really getting when buying?&lt;/p&gt;
&lt;h2&gt;1. You are buying expertise.&lt;/h2&gt;
&lt;p&gt;While your two engineers are probably excellent, they haven’t lived and breathed a space for years.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://sendgrid.com/"&gt;SendGrid&lt;/a&gt; team are experts at email delivery. While most developers can set up their own Email server they can’t tell you exactly why an Email isn’t getting delivered and how you can fix it.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://zencoder.com/"&gt;Zencoder&lt;/a&gt; team are experts at quickly converting any video into any format. They know where the browser and mobile market is going and can get you there faster.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://crocodoc.com/"&gt;Crocodoc&lt;/a&gt; team are experts at converting the many horrors of Microsoft products into HTML5. Every edge case can be properly rendered and look exactly the same on any platform.&lt;/p&gt;
&lt;h2&gt;2. You are buying time.&lt;/h2&gt;
&lt;p&gt;Anything that is outside of your core competency should be delegated to someone else. Unless you plan on competing with the company, you should probably just buy their product.&lt;/p&gt;
&lt;h2&gt;3. You are buying QA.&lt;/h2&gt;
&lt;p&gt;“Given enough eyeballs, all bugs are shallow”. When one developer finds a bug with an API, the community benefits. It’s almost impossible to catch all edge cases even with great testing practices. With a large community of developers and their users your QA department is almost infinite.&lt;/p&gt;
&lt;h2&gt;4. You are buying community.&lt;/h2&gt;
&lt;p&gt;There are a massive amount of talented engineers out there that are already building interesting products using any given API. A quick search of StackOverflow shows that there are &lt;a href="http://stackoverflow.com/questions/tagged/twilio"&gt;332&lt;/a&gt; questions tagged with Twilio, &lt;a href="http://stackoverflow.com/questions/tagged/sendgrid"&gt;208&lt;/a&gt; with SendGrid and &lt;a href="http://stackoverflow.com/questions/tagged/filepicker.io"&gt;164&lt;/a&gt; with filepicker.io to name a few.&lt;/p&gt;
&lt;p&gt;You are in good company when you buy.&lt;/p&gt;
&lt;h2&gt;5. You are buying scale.&lt;/h2&gt;
&lt;p&gt;Interesting things start to happen at scale. Embedly’s average response time has dropped dramatically over the past year. As the service has grown and more developers use the product there is a greater probability that a URL requested is already in cache. This allows use to respond quicker and I assume this is also the case with a company like FullContact.&lt;/p&gt;
&lt;h2&gt;6. You are buying relationships.&lt;/h2&gt;
&lt;p&gt;There is almost always someone upstream that can cause issues. Twilio has the Phone Companies, SendGrid has Email providers, FullContact has Social APIs, Filepicker has Dropbox and Embedly has Providers. At scale you have probably already cultivated relationships that when something fails you know exactly who to talk to.&lt;/p&gt;
&lt;p&gt;Embedly buys &lt;a href="http://mixpanel.com"&gt;MixPanel&lt;/a&gt;, &lt;a href="http://sendgrid.com"&gt;SendGrid&lt;/a&gt;, &lt;a href="http://fullcontact.com"&gt;FullContact&lt;/a&gt;, &lt;a href="http://zendesk.com"&gt;Zendesk&lt;/a&gt;, &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt; and &lt;a href="http://chargify.com"&gt;Chargify&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Who are you buying time from?&lt;/p&gt;</description><link>http://blog.embed.ly/post/50655830172</link><guid>http://blog.embed.ly/post/50655830172</guid><pubDate>Fri, 17 May 2013 11:28:00 -0400</pubDate><category>apis</category><dc:creator>screeley</dc:creator></item><item><title>Improve your drip campaigns with Mixpanel and FullContact</title><description>&lt;p&gt;By using &lt;a href="http://fullcontact.com"&gt;FullContact&lt;/a&gt; to push user profile data into &lt;a href="http://mixpanel.com"&gt;Mixpanel&lt;/a&gt; we’re able to make targeting and tracking more powerful. We can target drip marketing campaigns more precisely based on where our users work, as well as their social profiles, location or age.&lt;/p&gt;
&lt;p&gt;For those that are unfamiliar, Mixpanel helps you track your users and customers as they use your application, hopefully providing insight into how to increase conversion rates (&lt;a href="https://mixpanel.com/revenue/"&gt;“revenue analytics”&lt;/a&gt;). FullContact is a cool little API that takes an email address and provides lots of information about the person behind that address — his or her social network profiles, places of employment and some basic demographic information.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;We are trying to get to a place where we can trigger notifications based on personal attributes instead of just when they signed up. Here is an example of targeting made possible by FullContact and Mixpanel:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="http://media.tumblr.com/fa0c8df230179401ab8d6c2016dfa16f/tumblr_inline_mmwgpx5p6F1qz4rgp.png"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;The following is a short tutorial on using the FullContact API to push user data into Mixpanel.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;First off, this is what a user might look like in your Mixpanel project:&lt;/p&gt;
&lt;pre&gt;{
    "email": "sean@embed.ly",
    "plan": "basic",
    "date_joined": "May 1, 2012",
    "last_login": "May 10, 2013"
}
&lt;/pre&gt;
&lt;p&gt;This information is probably populated by your frontend via the Mixpanel javascript library, but it’s perfectly reasonable to do it in the backend as well. Fullcontact, however, is a separate API that you’ll have to call on your backend. Looking up an email address is very straightforward via its HTTP API:&lt;/p&gt;
&lt;pre&gt;$ curl "http://api.fullcontact.com/v2/person.json?email=sean@embed.ly&amp;amp;apiKey=YOURKEY"

{
  "status": 200,
  "likelihood": 0.89,
  "requestId": "aa2f9f2c-57b8-48ab-811b-1be24aa652c8",
  "photos": 
  ...
  "demographics": {
    "locationGeneral": "Boston",
    "gender": "Male"
  },
  ...
}
&lt;/pre&gt;
&lt;p&gt;Take a look at the &lt;a href="https://gist.github.com/JohnEmhoff/5591773"&gt;full response&lt;/a&gt; if you’d like to see what kind of information it can provide. Pretty simple, although there are a couple details to keep in mind:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Ocassionally Fullcontact will return HTTP 202 which indicates your search has been queued and that you should retry the request in a few minutes&lt;/li&gt;
&lt;li&gt;A status code of 404 means the query has run and no information was found&lt;/li&gt;
&lt;li&gt;Fullcontact will rate limit your requests based on your plan&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;This means you’ll want to do your lookups in batches, which might look something like this:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;def fullcontact_lookup(emails, api_key):
    results = {}
    to_lookup = set(emails)
    api_format = 'http://api.fullcontact.com/v2/person.json?email=%s&amp;amp;apiKey=%s'
    while len(to_lookup) &amp;gt; 0:
        # make a copy so we can delete from the set while we iterate
        for email in to_lookup.copy():
            api = api_format % (email, api_key)
            response = json.loads(requests.get(api).text)
            if response['status'] == 200:
                results[email] = response
                to_lookup.remove(email)
            elif response['status'] == 404:
                results[email] = None
                to_lookup.remove(email)
            elif response['status'] == 202:
                # keep it around to give it another go
                pass
            else:
                raise ValueError('Unexpected response from fullcontact: %s' %
                    json.dumps(response))
        # give fullcontact a minute to run some queries
        time.sleep(60)
    return results
&lt;/pre&gt;
&lt;p&gt;Now we need to actually stuff this data into Mixpanel. Unfortunately, naively running fullcontact_lookup against your entire database every night will be expensive, as Fullcontact charges per successful request. What we can do is add a property to each person called, say, fullcontact_version that keeps track of who has been queried. This can be an integer that gets incremented each time you change your schema, so you can just run the people with fullcontact_version&amp;#160;!= current_version. Treat the code below as pseudo-code; if you’d like to see the nitty gritty Mixpanel API details check out their &lt;a href="https://mixpanel.com/docs/"&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;def go(fullcontact_version):
    to_update = get_with_different_version(fullcontact_version)
    all_info = fullcontact_lookup(to_update)
    for person in to_update:
        info = all_info[person['email']]
        person['fullcontact_version'] = fullcontact_version
        if info:
            person['age'] = info.get('demographics', {}).get('age')
            # add more properties as you see fit
        save_person_to_mixpanel(person)
&lt;/pre&gt;
&lt;p&gt;And there it is! With this small amount of effort you can get greater insight into who your users are and the ability to communicate with them more efficiently.&lt;/p&gt;</description><link>http://blog.embed.ly/post/50575153611</link><guid>http://blog.embed.ly/post/50575153611</guid><pubDate>Thu, 16 May 2013 09:27:00 -0400</pubDate><category>fullcontact</category><category>mixpanel</category><dc:creator>thejohnnest</dc:creator></item><item><title>Display: An Image Proxy and Resizing API for Web Images</title><description>&lt;p&gt;&lt;span&gt;Our newest product is an Image Proxy and Image Resize API, fondly referred to as &lt;/span&gt;&lt;a href="http://embed.ly/display"&gt;Display&lt;/a&gt;&lt;span&gt;. This service is being thrown into the lime-light today to highlight its simplicity and usefulness for providing optimized 3rd party images to your web or mobile application.&lt;/span&gt;&lt;/p&gt;
&lt;p class="p2"&gt;&lt;span&gt;Display is useful in many situations, but we find that some of the most important features include its use as a proxy to provide SSL images and its ability to resize images, which not only decreases the file size, but also allows you to scale them to fit and load quickly in any mobile or web browser.&lt;/span&gt;&lt;/p&gt;
&lt;p class="p2"&gt;The Image Resize API is a great complement to any 3rd party media API aggregating photos and images of various sizes. It &lt;a href="http://embed.ly/docs/display/api/integration"&gt;integrates directly&lt;/a&gt; with our own &lt;a href="http://embed.ly/embed"&gt;Embed&lt;/a&gt; and &lt;a href="http://embed.ly/extract"&gt;Extract&lt;/a&gt; APIs to provide SSL images and resizing automatically.&lt;/p&gt;
&lt;p class="p2"&gt;&lt;a href="http://embed.ly/display"&gt;&lt;img alt="image" src="http://media.tumblr.com/13f6bf556d929182a9a4422c55f1b0f7/tumblr_inline_mmugj8xDw71qz4rgp.png"/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class="p2"&gt;See the Display image resize feature in action in &lt;a href="http://embed.ly/display/features/resize"&gt;the Resize demo&lt;/a&gt; or try some examples with &lt;a href="http://embedly.github.io/embedly-jquery/display.html"&gt;Embedly JQuery&lt;/a&gt;.&lt;a href="http://embedly.github.io/embedly-jquery/display.html"&gt;&lt;br/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class="p2"&gt;Images make your site more engaging, but they slow down page load time, and it&amp;#8217;s hard to optimize them for different screens.  Display solves that problem. Sign up to &lt;a href="https://app.embed.ly/signup"&gt;get started with Display&lt;/a&gt;.&lt;/p&gt;</description><link>http://blog.embed.ly/post/50497413300</link><guid>http://blog.embed.ly/post/50497413300</guid><pubDate>Wed, 15 May 2013 10:36:00 -0400</pubDate><category>image resize api</category><category>image proxy</category><category>ssl images</category><category>display</category><dc:creator>artgibby</dc:creator></item><item><title>Vine's not a rocket ship, but it's doing well outside of Twitter </title><description>&lt;p&gt;&lt;span&gt;Vine is doing well outside of Twitter, better than it&amp;#8217;s competitors, but it&amp;#8217;s not a rocket ship.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We set out to measure the rise of Vine as a provider and see how it compares to other mobile video sharing tools. Here are the total URLs that we have seen posted to Embedly&amp;#8217;s API since Vine launched on January 24, 2013:&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="http://media.tumblr.com/3837f7003390db7d70c3ed1781aaf332/tumblr_inline_mml6cfWWYb1qz4rgp.png"/&gt;&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll see a nice bump post launch and the classic exponential growth that you would like to see, but that wore off after about a week. Vine&amp;#8217;s competitors are barely a blip on the radar, so let&amp;#8217;s look at this graph on a logarithmic scale:&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="http://media.tumblr.com/d390f15bf518fc3b0d36433b6e9f214c/tumblr_inline_mml6cq7oAF1qz4rgp.png"/&gt;&lt;/p&gt;

&lt;p&gt;Vine still dominates, SocialCam seems to do a bit better than Qik and Viddy who are about equal. &lt;/p&gt;
&lt;p&gt;How many URLs we get through the system is not that important because that can change on any day due to one client hammering us with all Vine URLs. It&amp;#8217;s more about many different developers are requesting a certain provider along with velocity.&lt;/p&gt;
&lt;p&gt;The following chart scores providers based on the number of URLs and the diversity of developers. It is a little more telling of how well Vine is doing:&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="http://media.tumblr.com/e6086b12b2a6487a396e7d620be9fda5/tumblr_inline_mml6d4oqWz1qz4rgp.png"/&gt;&lt;/p&gt;

&lt;p&gt;Vine is trending up, while the rest have a slight trend downwards.&lt;/p&gt;
&lt;p&gt;Vine is getting some good distribution throughout the long tail and it&amp;#8217;s pretty clear why Viddy is giving back 18 million dollars.&lt;/p&gt;
&lt;p&gt;Finally, to put this in perspective we did 1,345,449 YouTube URLS, 243,897 Instagram URLs and 25,892 Vine URLs yesterday. Vine still has a long way to go.&lt;/p&gt;</description><link>http://blog.embed.ly/post/50090097404</link><guid>http://blog.embed.ly/post/50090097404</guid><pubDate>Fri, 10 May 2013 10:30:00 -0400</pubDate><category>vine</category><category>twitter</category><category>stats</category><category>data</category><category>video</category><dc:creator>screeley</dc:creator></item><item><title>Ember at Embedly Tutorial: Models and Ember Data</title><description>&lt;style&gt;
dl.table-display
{
  float: left;
  width: 720px;
  margin: 1em 0;
  padding: 0;
  border-bottom: 1px solid #999;
}
  
.table-display dt
{
  clear: left;
  float: left;
  width: 200px;
  margin: 0;
  padding: 5px;
  border-top: 1px solid #999;
  font-weight: bold;
}
  
.table-display dd
{
  float: left;
  width: 500px;
  margin: 0;
  padding: 5px;
  border-top: 1px solid #999;
}
&lt;/style&gt;&lt;p&gt;
In this fourth post in our series on Ember, we will continue to work from the 
&lt;a href="https://github.com/screeley/ember-demo-environment" target="_blank"&gt;
development environment&lt;/a&gt; that we worked on in the
&lt;a href="http://blog.embed.ly/post/46586649344/introduction-to-ember-development" target="_blank"&gt;first&lt;/a&gt; 
&lt;a href="http://blog.embed.ly/post/47205604241/ember-at-embedly-templates-and-the-router" target="_blank"&gt;three&lt;/a&gt;
&lt;a href="http://blog.embed.ly/post/48039881005/ember-at-embedly-views-and-controllers" target="_blank"&gt;posts&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
This installment will focus on models, backed by RESTful storage, using
ember-data. First, a &lt;span style="color: blue; font-size: 2em; text-weight: bold;"&gt;giant, red, warning&lt;/span&gt;: ember-data
is not production ready. It is under active development and changes often.
There are bugs and limitations and you&amp;#8217;ll have to wait for them to be
fixed. We at Embedly, in our youthful exuberance, decided to ignore these
problems and blaze forward into the future! If you do decide to follow us, stay
up-to-date with breaking changes at
&lt;a href="https://github.com/emberjs/data/blob/master/BREAKING_CHANGES.md" target="_blank"&gt;BREAKING_CHANGES.md&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
As usual, you can find the complete code for the demo project at
&lt;a href="https://github.com/screeley/ember-demo-environment" target="_blank"&gt;
github&lt;/a&gt;. We won&amp;#8217;t cover every code change here, just the ones directly
related to ember models and ember-data.
&lt;/p&gt;

&lt;p&gt;
If you remember, in our 
&lt;a href="http://blog.embed.ly/post/48039881005/ember-at-embedly-views-and-controllers"&gt;last&lt;/a&gt;
installment, we created a team page. We used fixtures to provide data
to the template. Let&amp;#8217;s switch out these fixtures for some data provided by
a RESTful api. We&amp;#8217;ve built a simple api server in node.js to connect to. It is
only an example and does the bare minimum to get us up and running. Please
don&amp;#8217;t consider using it for anything remotely serious.
&lt;/p&gt;

&lt;h3&gt;Adding ember-data&lt;/h3&gt;
&lt;p&gt;
We are using &lt;code&gt;bower&lt;/code&gt; to manage our javascript dependencies.
There is an ember-data wrapper, called &lt;code&gt;ember-data-shim&lt;/code&gt;, made
specifically for dependency management. If you use it, make sure it is
relatively up-to-date when you add it to your own project. Here is our new
component.json.
&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
    // bower.json

    {
      "name": "demo",
      "version": "0.0.0",
      "dependencies": {
        "modernizr": "~2.6.2",
        "jquery": "~1.9.1",
        "handlebars": "1.0.0-rc.3",
        "ember": "1.0.0-rc.3",
        "ember-data-shim": "0.0.12"
      },
      "devDependencies": {}
    }
&lt;/pre&gt;

&lt;p&gt;
Running &lt;code&gt;bower install&lt;/code&gt; will install the dependency into our
&lt;code&gt;app/components&lt;/code&gt; path. Now we just have to add
&lt;code&gt;ember-data.js&lt;/code&gt; to our &lt;code&gt;app/index.html&lt;/code&gt;.
&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
    // app/index.html

    &lt;em&gt;- snip -&lt;/em&gt;
    &amp;lt;script src="components/ember/ember.js"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src="components/ember-data-shim/ember-data.js"&amp;gt;&amp;lt;/script&amp;gt;
    &lt;em&gt;- snip -&lt;/em&gt;
&lt;/pre&gt;

&lt;p&gt;
If everything went as planned, we should be able to start the app, open it in
the browser, and check to see if there is a global &lt;code&gt;DS&lt;/code&gt; object
available in the browser&amp;#8217;s javascript console.
&lt;/p&gt;

&lt;h3&gt;Configuring ember-data&lt;/h3&gt;
&lt;p&gt;
There is a little bit of configuration to do to get ember-data
working. We&amp;#8217;ll add it to &lt;code&gt;app/scripts/main.js&lt;/code&gt;. The first part tells
ember-data what version we are planning on using. This is important since the
API has breaking changes between revisions. We don&amp;#8217;t want to accidentally upgrade
before we are ready. The second section tells the &lt;code&gt;RESTAdapter&lt;/code&gt; the
base URL for our RESTful api.
&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
    // app/scripts/main.js

    &lt;em&gt;- snip -&lt;/em&gt;
    App.Store = DS.Store.extend({
      revision: 12
    });

    DS.RESTAdapter.reopen({
      url: '/rest/1'
    });

    &lt;em&gt;- snip -&lt;/em&gt;
&lt;/pre&gt;

&lt;p&gt;
You may be asking yourself, what is the RESTAdapter, and what other adapters
are there? Ember-data comes packaged with a RESTAdapter and
FixtureAdapter. The &lt;code&gt;FixtureAdapter&lt;/code&gt; provides an in memory browser
store and is mostly useful for testing and development.
&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;FixtureAdapter&lt;/code&gt; was an option when writing this post, but
I also wanted to show the expected responses and results of the API calls,
so that when you go to implement your own RESTful service, you&amp;#8217;ll know what
to expect.
&lt;/p&gt;

&lt;h3&gt;Defining Our Model&lt;/h3&gt;
&lt;p&gt;
Defining our model is very simple. First we&amp;#8217;ll remove all our &amp;#8220;Fixtures&amp;#8221; from
&lt;code&gt;app/scripts/modules/about.js&lt;/code&gt;, and replace them with our model
definitions in &lt;code&gt;app/scripts/modules/models.js&lt;/code&gt;.
&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
    // app/scripts/modules/models.js

    App.Org = DS.Model.extend({
      name: DS.attr('string'),
      description: DS.attr('string'),
      members: DS.hasMany('App.Member')
    });

    App.Member = DS.Model.extend({
      name: DS.attr('string'),
      org: DS.belongsTo('App.Org')
    });

    // app/index.html

    &lt;em&gt;- snip -&lt;/em&gt;
    &amp;lt;script src="scripts/modules/models.js"&amp;gt;&amp;lt;/script&amp;gt;
    &lt;em&gt;- snip -&lt;/em&gt;
&lt;/pre&gt;

&lt;p&gt;
Here we are only using the &lt;code&gt;string&lt;/code&gt; attr type, but string, number,
boolean, and date are also available. It is also possible to define your own
attr types as well, but we won&amp;#8217;t cover that here.
&lt;/p&gt;

&lt;p&gt;
We are also defining a many-to-one relationship between &lt;code&gt;Member&lt;/code&gt; and
&lt;code&gt;Org&lt;/code&gt;. We really only have one &lt;code&gt;Org&lt;/code&gt;, but who knows how
our site will grow in the future. It is possible to declare many-to-many
relationships, but let&amp;#8217;s keep things simple.
&lt;/p&gt;


&lt;h3&gt;Wiring up our Route and Controller&lt;/h3&gt;

&lt;p&gt;
Let&amp;#8217;s update the about page to use our new model, replacing our old fixture
code.
&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
    // app/scripts/main.js

    App = Em.Application.create({
      rootElement: $('#app'),
      orgId: 0
    });
    &lt;em&gt;- snip -&lt;/em&gt;

    // app/scripts/modules/about.js

    &lt;em&gt;- snip -&lt;/em&gt;
    App.AboutRoute = Em.Route.extend({
      model: function() {
        return App.Org.find(App.get('orgId'));
      }
    });

    // app/templates/about.handlebars

    &lt;em&gt;- snip -&lt;/em&gt;
    {{render "team" controller.members}}
    
&lt;/pre&gt;

&lt;p&gt;
We&amp;#8217;ve configured our &lt;code&gt;orgId&lt;/code&gt; in the &lt;code&gt;App&lt;/code&gt; object. This is
a good place to put site-wide configuration. Next we replaced our fixture with
a call to &lt;code&gt;App.Org.find()&lt;/code&gt; in our &lt;code&gt;Route#model&lt;/code&gt;. &lt;code&gt;
ember-data&lt;/code&gt; will return an empty object, then switch in the
&lt;code&gt;Org&lt;/code&gt; when it&amp;#8217;s ready. Since Ember.js is so wonderful, it will
re-render the relevant parts of the view on update. Finally, we replace the
members fixture in the &lt;code&gt;about.handlebars&lt;/code&gt; with the
&lt;code&gt;members&lt;/code&gt; field of the &lt;code&gt;Org&lt;/code&gt; object, which is an Array
of organization members.
&lt;/p&gt;

&lt;p&gt;
Now our application behaves exactly the same as it did before we implemented
ember-data, except that it is backed by a RESTful API. Pretty
simple, eh? But not very interesting, we&amp;#8217;ll have to add some CRUD operations to
truly demonstrate ember-data&amp;#8217;s power. Let&amp;#8217;s take a look at,
what&amp;#8217;s happening between the server and client before we move on to mutating
the data.
&lt;/p&gt;

&lt;p&gt;
Retrieving records using ember-data is extremely simple. One
thing to keep in mind is that it&amp;#8217;s asynchronous. Usually you can safely ignore
that fact, due to the way ember&amp;#8217;s event system works, but sometimes it can
bite you, so keep it in mind. We retrieve our &lt;code&gt;Org&lt;/code&gt; with the line
&lt;code&gt;App.Org.find(App.get('orgId'))&lt;/code&gt;. Let&amp;#8217;s take a look at what our
server returns.
&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
  // Request

  GET /rest/1/orgs/0

  // Response

  {
    "org": {
      "name": "jubarian.org",
      "description": "A non-profit organization of people...",
      "member_ids": [ 0, 1, 2, 3, 4, 5, 6 ]
    },
    "members": [{
      "org_id": 0,
      "name": "Nina",
      "id": 0
    }, {
      "org_id": 0,
      "name": "Kawan",
      "id": 1
  &lt;em&gt;- snip -&lt;/em&gt;
    }]
  }
&lt;/pre&gt;

&lt;p&gt;
There are a few things to be aware of here. First, we can see that our API
puts the payload of the org object into a field called
&lt;code&gt;org&lt;/code&gt; (singular). This is where ember-data will look for the
&lt;code&gt;Org&lt;/code&gt; data. If we had made a more general query that returned a
list, it would be &lt;code&gt;orgs&lt;/code&gt; in the plural form. Second, we are also
returning all the members data with the response. This is referred to as
side-loading, and it is optional. In our case, since we have the luxury of a
very small application with well defined requirements, we know that this is the
most efficient way to do things. If we didn&amp;#8217;t side-load, ember-data
will make another call to retrieve the data when it&amp;#8217;s needed.
&lt;/p&gt;

&lt;p&gt; Notice that the &lt;code&gt;members&lt;/code&gt; field is plural, it&amp;#8217;s a list, and ids
are included in the objects. Also notice the serialization of the data fields.
Ember expects all serialized field names to be underscore separated, even
though it expects camelcase in the javascript models. It also expects a
pluralized &lt;code&gt;member_ids&lt;/code&gt; field for the one-to-many relationship, and
a singular &lt;code&gt;org_id&lt;/code&gt; for the many-to-one relationship.  &lt;/p&gt;

&lt;p&gt;
All of these behaviors can be modified. Ember-data is very customizable, but
unless you are dealing with a legacy API, it&amp;#8217;s always best to conform with
the frameworks expectations.
&lt;/p&gt;

&lt;h3&gt;Ember Data&amp;#8217;s Protocol&lt;/h3&gt;

&lt;p&gt;
Let&amp;#8217;s give a brief overview of what ember-data expects to send and
receive during different transactions. Understanding this protocol will not
only help you implement your own persistent backend, but also is invaluable for
debugging ember-data errors, which are often the result of some
unexpected data. Many of these details can be modified by configuring the
&lt;code&gt;RESTAdapter&lt;/code&gt;, but again, if possible, it&amp;#8217;s better to stick with the
standard. Keep in mind that if you have an existing API that is much different,
it might be worth writing your own adapter. We won&amp;#8217;t cover custom adapters in
this post.
&lt;/p&gt;

&lt;h4&gt;GET one&lt;/h4&gt;
&lt;dl class="table-display"&gt;&lt;dt&gt;Call&lt;/dt&gt;
  &lt;dd&gt;&lt;pre class="prettyprint"&gt;find(:id)&lt;/pre&gt;&lt;/dd&gt;

  &lt;dt&gt;HTTP Method&lt;/dt&gt;
  &lt;dd&gt;GET&lt;/dd&gt;

  &lt;dt&gt;URL&lt;/dt&gt;
  &lt;dd&gt;/&amp;lt;plural model&amp;gt;/:id&lt;/dd&gt;

  &lt;dt&gt;Example Request&lt;/dt&gt;
  &lt;dd&gt;GET /orgs/0&lt;/dd&gt;

  &lt;dt&gt;Example Response&lt;/dt&gt;
  &lt;dd&gt;
    &lt;pre class="prettyprint"&gt;
{
  "org": {
    "name": "jubarian.org",
    "description": "A non-profit organization of people...",
    "member_ids": [ 0, 1, 2, 3, 4, 5, 6 ]
  }
}&lt;/pre&gt;
  &lt;/dd&gt;
&lt;/dl&gt;&lt;div style="clear: both;"&gt;&lt;/div&gt;

&lt;h4&gt;GET many&lt;/h4&gt;
&lt;dl class="table-display"&gt;&lt;dt&gt;Call&lt;/dt&gt;
  &lt;dd&gt;&lt;pre class="prettyprint"&gt;find({:attr: :value}&lt;/pre&gt;&lt;/dd&gt;

  &lt;dt&gt;HTTP Method&lt;/dt&gt;
  &lt;dd&gt;GET&lt;/dd&gt;

  &lt;dt&gt;URL&lt;/dt&gt;
  &lt;dd&gt;/&amp;lt;plural model&amp;gt;?:attr=:value&lt;/dd&gt;

  &lt;dt&gt;Example Request&lt;/dt&gt;
  &lt;dd&gt;GET /orgs?name=jubarian.org&lt;/dd&gt;

  &lt;dt&gt;Example Response&lt;/dt&gt;
  &lt;dd&gt;
    &lt;pre class="prettyprint"&gt;
{
  "orgs": [
    {
      "id": 0,
      "name": "jubarian.org",
      "description": "A non-profit organization of people...",
      "member_ids": [ 0, 1, 2, 3, 4, 5, 6 ]
    }
  ]
}&lt;/pre&gt;
  &lt;/dd&gt;
&lt;/dl&gt;&lt;div style="clear: both;"&gt;&lt;/div&gt;

&lt;p&gt;
With mutations, we need to commit our changes before they will be sent
to the server, either through the records transaction or the store. If
we change our minds before we commit, we can invoke &lt;code&gt;rollback&lt;/code&gt;
instead of &lt;code&gt;commit&lt;/code&gt;.
&lt;/p&gt;

&lt;h4&gt;POST&lt;/h4&gt;
&lt;dl class="table-display"&gt;&lt;dt&gt;Call&lt;/dt&gt;
  &lt;dd&gt;
    &lt;pre class="prettyprint"&gt;
var record = Model.createRecord({...});
record.get('store').commit();&lt;/pre&gt;
  &lt;/dd&gt;

  &lt;dt&gt;HTTP Method&lt;/dt&gt;
  &lt;dd&gt;POST&lt;/dd&gt;

  &lt;dt&gt;URL&lt;/dt&gt;
  &lt;dd&gt;/&amp;lt;plural model&amp;gt;&lt;/dd&gt;

  &lt;dt&gt;Example Request&lt;/dt&gt;
  &lt;dd&gt;POST /members&lt;/dd&gt;

  &lt;dt&gt;Example Body&lt;/dt&gt;
  &lt;dd&gt;
    &lt;pre class="prettyprint"&gt;
{"member":{"name":"Billy","org_id":0}} 
    &lt;/pre&gt;
  &lt;/dd&gt;

  &lt;dt&gt;Example Response&lt;/dt&gt;
  &lt;dd&gt;
    &lt;pre class="prettyprint"&gt;
{"member":{"name":"Billy","org_id":0, "id": 7}} 
    &lt;/pre&gt;
  &lt;/dd&gt;
&lt;/dl&gt;&lt;div style="clear: both;"&gt;&lt;/div&gt;

&lt;h4&gt;PUT&lt;/h4&gt;
&lt;dl class="table-display"&gt;&lt;dt&gt;Call&lt;/dt&gt;
  &lt;dd&gt;
    &lt;pre class="prettyprint"&gt;
var record = Model.find(:id);
record.set(:name, :value);
record.get('store').commit();&lt;/pre&gt;
  &lt;/dd&gt;

  &lt;dt&gt;HTTP Method&lt;/dt&gt;
  &lt;dd&gt;PUT&lt;/dd&gt;

  &lt;dt&gt;URL&lt;/dt&gt;
  &lt;dd&gt;/&amp;lt;plural model&amp;gt;/:id&lt;/dd&gt;

  &lt;dt&gt;Example Request&lt;/dt&gt;
  &lt;dd&gt;PUT /members/7&lt;/dd&gt;

  &lt;dt&gt;Example Body&lt;/dt&gt;
  &lt;dd&gt;
    &lt;pre class="prettyprint"&gt;{"member":{"name":"William","org_id":0}}&lt;/pre&gt;
  &lt;/dd&gt;

  &lt;dt&gt;Example Response&lt;/dt&gt;
  &lt;dd&gt;
    &lt;pre class="prettyprint"&gt;{"member":{"name":"William","org_id":0}}&lt;/pre&gt;
  &lt;/dd&gt;
&lt;/dl&gt;&lt;div style="clear: both;"&gt;&lt;/div&gt;

&lt;p&gt;
One thing to note is that &lt;code&gt;DELETE&lt;/code&gt; MUST return valid json, or you
will get an error. I consider this a bug, so hopefully it changes in the
future.
&lt;/p&gt;

&lt;h4&gt;DELETE&lt;/h4&gt;
&lt;dl class="table-display"&gt;&lt;dt&gt;Call&lt;/dt&gt;
  &lt;dd&gt;
    &lt;pre class="prettyprint"&gt;
var record = Model.find(:id);
  
record.deleteRecord();
record.get('store').commit();&lt;/pre&gt;
  &lt;/dd&gt;

  &lt;dt&gt;HTTP Method&lt;/dt&gt;
  &lt;dd&gt;DELETE&lt;/dd&gt;

  &lt;dt&gt;URL&lt;/dt&gt;
  &lt;dd&gt;/&amp;lt;plural model&amp;gt;/:id&lt;/dd&gt;

  &lt;dt&gt;Example Request&lt;/dt&gt;
  &lt;dd&gt;DELETE /members/7&lt;/dd&gt;

  &lt;dt&gt;Example Response&lt;/dt&gt;
  &lt;dd&gt;
    &lt;pre class="prettyprint"&gt;{}&lt;/pre&gt;
  &lt;/dd&gt;
&lt;/dl&gt;&lt;div style="clear: both;"&gt;&lt;/div&gt;

&lt;h3&gt;Creating a Team Admin Page&lt;/h3&gt;

&lt;p&gt;
Next, let&amp;#8217;s put it all together and build a member management section for our
site. First let&amp;#8217;s setup the routes. We&amp;#8217;ll have three pages; an index, a new
member form and an edit member form.
&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
    // app/scripts/main.js

    &lt;em&gt;- snip -&lt;/em&gt;
    App.Router.map(function(){
      this.route('about');
      this.resource('members', function() {
        this.route('new');
        this.route('edit', {path: '/edit/:id'});
      });
    });
    &lt;em&gt;- snip -&lt;/em&gt;
&lt;/pre&gt;

&lt;p&gt;
Now, let&amp;#8217;s build the Routes and Controllers.
&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
    // app/scripts/modules/members.js

    App.MembersIndexRoute = Em.Route.extend({
      setupController: function(controller, model) {
        App.Org.find(App.get('orgId')).then(function(org) {
          controller.set('content', org.get('members'))
        });
        controller.set('content', Em.A());
      }
    })

    App.MembersEditRoute = Em.Route.extend({
      serialize: function(obj) {
        return {id: obj.get('id')};
      },
      model: function(params) {
        return App.Member.find(params.id);
      }
    })

    App.MembersNewRoute = Em.Route.extend({
      model: function(params) {
        return Em.Object.create({org: App.Org.find(App.get('orgId'))});
      }
    })

    /*
     * Wrap member model objects in simple interface callable
     * by the view.
     */
    App.MemberController = Em.ObjectController.extend({
      "delete": function() {
        this.get('content').deleteRecord();
        this.get('store').commit();
      },
      edit: function() {
        this.transitionToRoute("members.edit", this);
      },
      save: function() {
        this.get('store').commit();
        this.transitionToRoute("members.index");
      },
      cancel: function() {
        this.get('store.defaultTransaction').rollback();
        this.transitionToRoute("members.index");
      },
      create: function() {
        this.set('content', App.Member.createRecord(this.get('content')));
        this.save();
      },
      cancelNew: function() {
        this.transitionToRoute("members.index");
      }
    })

    App.MembersIndexController = Em.ArrayController.extend({
      itemController: "member"
    })

    App.MembersNewController = App.MemberController.extend({});
    App.MembersEditController = App.MemberController.extend({});

    // app/index.html

    &lt;em&gt;- snip -&lt;/em&gt;
    &amp;lt;script src="scripts/modules/members.js"&amp;gt;&amp;lt;/script&amp;gt;
    &lt;em&gt;- snip -&lt;/em&gt;
&lt;/pre&gt;

&lt;p&gt;
If you&amp;#8217;ll notice, in &lt;code&gt;MembersIndexController&lt;/code&gt; we forgo using the
&lt;code&gt;model&lt;/code&gt; callback in favor of the &lt;code&gt;setupController&lt;/code&gt;
callback. This is because we are passing in a field of the result of an
asynchronous operation. &lt;code&gt;MembersIndexController&lt;/code&gt; needs an
&lt;code&gt;Array&lt;/code&gt; right away to set itself up. If we called something like
&lt;code&gt;Members.find({org_id: 0})&lt;/code&gt; then ember-data would have returned an
empty array right away and we would have been fine, but I wanted to showcase a
situation where the asynchronous nature of ember-data can leak through, so it&amp;#8217;s
important to be aware of. Once the call has returned, we can safely swap the
result into the controllers &lt;code&gt;content&lt;/code&gt; field and everything will be
updated as expected.
&lt;/p&gt;

&lt;p&gt;
We&amp;#8217;ve also introduced a new controller callback &lt;code&gt;serialize&lt;/code&gt;, in
the &lt;code&gt;MembersEditController&lt;/code&gt;. If your Route has parameters, it is
important to provide a way to map the object it represents to the URL
parameters. This way when we transition to the route and pass an object
directly to it, ember can form a linkable URL out of it. Our serialize method
maps the &lt;code&gt;id&lt;/code&gt; attribute of the model to the &lt;code&gt;id&lt;/code&gt;
parameter in the edit URL.
&lt;/p&gt;

&lt;p&gt;
Our &lt;code&gt;MembersIndexController&lt;/code&gt; introduces the concept of
&lt;code&gt;itemController&lt;/code&gt;. &lt;code&gt;itemController&lt;/code&gt; wraps each item in an
&lt;code&gt;ArrayController&lt;/code&gt;, making it easier to perform actions on individual
items from the view. In our case, it will allow us to easily delete and edit
the individual items.
&lt;/p&gt;

&lt;p&gt;
We used inheritance to get all the functionality of
&lt;code&gt;MemberController&lt;/code&gt; into &lt;code&gt;MembersEditController&lt;/code&gt; and
&lt;code&gt;MembersNewController&lt;/code&gt;. Since we haven&amp;#8217;t added any view logic, we
are using the default generated views. Let&amp;#8217;s finish up by adding templates for
our member management pages, and a link from the about page.
&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
    // app/templates/about.handlebars

    &lt;em&gt;- snip -&lt;/em&gt;
    &amp;lt;p&amp;gt;
      &amp;lt;a href="#" {{action toggleTeam}}&amp;gt;{{toggleTeamLabel}}&amp;lt;/a&amp;gt;
      {{#linkTo members.index}}manage team{{/linkTo}}
    &amp;lt;/p&amp;gt;
    &lt;em&gt;- snip -&lt;/em&gt;

    // app/templates/members.handlebars

    &amp;lt;p&amp;gt;{{#linkTo "about"}}about{{/linkTo}}&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;{{outlet}}&amp;lt;/p&amp;gt;

    // app/templates/members/index.handlebars

    &amp;lt;p&amp;gt;List Members&amp;lt;/p&amp;gt;
    &amp;lt;ul&amp;gt;
    {{#each controller}}
      &amp;lt;li&amp;gt;
        {{name}} &amp;lt;a href="#" {{action delete}}&amp;gt;delete&amp;lt;/a&amp;gt; &amp;lt;a href="#" {{action edit}}&amp;gt;edit&amp;lt;/a&amp;gt;
      &amp;lt;/li&amp;gt;
    {{/each}}
    &amp;lt;/ul&amp;gt;
    {{#linkTo "members.new"}}add member{{/linkTo}}

    // app/templates/members/edit.handlebars

    &amp;lt;p&amp;gt;Edit Member&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;label&amp;gt;
      Name
      {{view Em.TextField valueBinding="name"}}
    &amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;
    &amp;lt;a href="#" {{action save}}&amp;gt;save&amp;lt;/a&amp;gt;
    &amp;lt;a href="#" {{action cancel}}&amp;gt;cancel&amp;lt;/a&amp;gt;
    &amp;lt;/p&amp;gt;

    // app/templates/members/new.handlebars

    &amp;lt;p&amp;gt;Create Member&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;label&amp;gt;
      Name
      {{view Em.TextField valueBinding="name"}}
    &amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;
    &amp;lt;a href="#" {{action create}}&amp;gt;save&amp;lt;/a&amp;gt;
    &amp;lt;a href="#" {{action cancelNew}}&amp;gt;cancel&amp;lt;/a&amp;gt;
    &amp;lt;/p&amp;gt;
&lt;/pre&gt;

&lt;h3&gt;Security&lt;/h3&gt;

&lt;p&gt;
Obviously, if this were a real application we wouldn&amp;#8217;t want just anybody to
be able to modify our member list. We&amp;#8217;d have to implement some security, but
that is outside the scope of this series of articles. One thing to be aware of
is that your RESTful API is publicly available, so make sure your security is
implemented there, and not on the frontend. Your ember app should be aware
of security, but your API should enforce it.
&lt;/p&gt;

&lt;h3&gt;Error Handling&lt;/h3&gt;

&lt;p&gt;
Error handling in ember-data leaves much to be desired, and
this is where the fact that it&amp;#8217;s a beta project is really obvious. It&amp;#8217;s
possible to build some error handling via callbacks and states on model
objects, but it&amp;#8217;s difficult and ever changing. Even finding documentation on
the relevant callbacks and states is difficult. It usually involves reading the
ember-data code base. We&amp;#8217;ve chosen to skip it in this article. It would be of
little lasting value, since we expect it to mature rather quickly.
&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;
I hope this article, and this series has been able to give you a good high
level understanding of ember and ember-data and get you quickly started on
the right path. Even if you choose not to use ember-data and
roll-your-own, I hope this article has given you some ideas on how to build
it. This wraps up our series on Ember at Embedly. Now go create something
awesome!
&lt;/p&gt;</description><link>http://blog.embed.ly/post/50012690904</link><guid>http://blog.embed.ly/post/50012690904</guid><pubDate>Thu, 09 May 2013 10:11:00 -0400</pubDate><category>dokipen</category><category>emberjs</category><category>javascript</category><dc:creator>dokipen</dc:creator></item><item><title>Bulk Usage Tiers</title><description>&lt;p&gt;&lt;span&gt;Today we are unveiling bulk usage tiers across all products. These tiers will provide you with a discounted cost as your use of the service increases&lt;/span&gt;&lt;span&gt;—&lt;/span&gt;&lt;span&gt;revolutionary! These changes will be available immediately and automatically occur for anyone using one of our new products.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re getting the news late, we announced &lt;a href="http://blog.embed.ly/post/46341258351/we-made-it"&gt;Products&lt;/a&gt; back in late March as a way to create the best front-end tools and services on the web. One of our main goals with the products was to scale, and pricing seemed like a good place to start.&lt;/p&gt;
&lt;p&gt;You can check out the usage tiers and use our handy calculator on each product&amp;#8217;s pricing page&lt;span&gt;—&lt;/span&gt;&lt;a href="http://embed.ly/display/pricing#tiers"&gt;Display&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;&lt;a href="http://embed.ly/embed/pricing#tiers"&gt;Embed&lt;/a&gt;&lt;span&gt;, and &lt;/span&gt;&lt;a href="http://embed.ly/extract/pricing#tiers"&gt;Extract&lt;/a&gt;&lt;span&gt;. Here&amp;#8217;s a glimpse of the Embed product&amp;#8217;s usage tiers:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;img alt="image" src="http://media.tumblr.com/01971704aaf16a5ba20a2b594b3b19f4/tumblr_inline_mm4tgfVvKZ1qz4rgp.png"/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Have any questions? Just give us a jingle: sales@embed.ly. If you haven&amp;#8217;t tried any of our products, sign up for our &lt;a href="https://app.embed.ly/signup"&gt;free intro&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</description><link>http://blog.embed.ly/post/49371264445</link><guid>http://blog.embed.ly/post/49371264445</guid><pubDate>Wed, 01 May 2013 14:00:00 -0400</pubDate><category>tiers pricing</category><dc:creator>artgibby</dc:creator></item><item><title>User Spotlight: Summary.io</title><description>&lt;div class="post_title"&gt;&lt;span&gt;This week we’re spotlighting recently launched &lt;/span&gt;&lt;a href="http://summary.io/"&gt;summary.io&lt;/a&gt;,&lt;span&gt; and the founder, &lt;/span&gt;&lt;a href="https://twitter.com/snellingmobile"&gt;Sam Sneeling&lt;/a&gt;&lt;span&gt;.&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;Here we go, &lt;strong&gt;what is the mission behind summary.io?&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Summary.io was built as a proof of a concept that you can summarize a large amount of news in a short period of time. The overall goal for our first version is to enable people to find articles that they want to read. The technology that powers it can really be applied to almost any body of text. We are looking at how summarizing text can make an impact in everyday lives.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;How does Embedly help with that mission?&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Embedly really helps us &lt;a href="http://embed.ly/extract"&gt;look good&lt;/a&gt; (by providing images for our news summaries). As of right now, Embedly is used as a fallback, but it works consistently. Really helps overall to have a reliable backend.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;What would you like to see next from Embedly?&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think Embedly has a lot to offer. Digging into your docs, your kitchen sink api is really quite incredible. I look forward to seeing that api become more available for a lower cost so that small developers can create really cool stuff.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you&amp;#8217;re interested in using our natural language processing and text extraction tools, check out our new product, &lt;a href="http://embed.ly/extract"&gt;Extract&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://app.embed.ly/signup"&gt;Sign up&lt;/a&gt; and get 5,000 calls per month free.&lt;/p&gt;</description><link>http://blog.embed.ly/post/49196438187</link><guid>http://blog.embed.ly/post/49196438187</guid><pubDate>Mon, 29 Apr 2013 16:38:00 -0400</pubDate><category>ninerr</category><category>summaryio</category><category>natural language processing</category><category>nlp</category><category>text extraction</category><category>extract</category><category>spotlight</category><dc:creator>ninerr</dc:creator></item><item><title>Startup Institute Boston Expose</title><description>&lt;p&gt;Yesterday, &lt;a href="http://www.twitter.com/kawantum"&gt;Kawan&lt;/a&gt; and &lt;a href="http://twitter.com/ninerr"&gt;I&lt;/a&gt; ventured to the &lt;a href="http://ilab.harvard.edu/"&gt;Harvard Innovation Lab&lt;/a&gt; on a beautiful day in Boston to see the graduating class of &lt;a href="http://venturefizz.com/slideshow/startup-institue-spring-13-students-slideshow"&gt;Startup Institute Boston&amp;#8217;s Spring Track&lt;/a&gt;. 50 hard-working and passionate individuals gave unique, expressive one-minute pitches in front of a &lt;a href="https://proximate.com/events/startup-institute-student-expose-spring-2013"&gt;crowd&lt;/a&gt; full of Boston based companies looking to hire.&lt;/p&gt;
&lt;p&gt;After each pitch from web developers, sales, marketing, and product design students, a networking session commenced. We met a ton of talented folks and had a great time doing it. As each student talked about their accomplishments, Kawan and I would sort of look at each other with wide eyes because we were so impressed by the amount of life experiences and ambition they had.  &lt;span&gt;We&amp;#8217;re excited to be connecting with the Boston startup community.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If you had a fun time and want to chat with us some more, or didn&amp;#8217;t get to meet myself or Kawan, venture out to sunny North Station next Friday from 11am to 1pm for &lt;a href="http://walkaboutembedly.eventbrite.com/"&gt;our stop on the Startup Walkabout&lt;/a&gt;. We&amp;#8217;ll be having lunch and beers, so come out and meet the rest of the team!&lt;/p&gt;</description><link>http://blog.embed.ly/post/48958337876</link><guid>http://blog.embed.ly/post/48958337876</guid><pubDate>Fri, 26 Apr 2013 18:27:05 -0400</pubDate><category>ninerr</category><category>startup institute boston</category><category>startups</category><category>harvard innovation lab</category><dc:creator>ninerr</dc:creator></item><item><title>Separating from the Flock</title><description>&lt;p&gt;As of May 24th we will no longer support Twitter Embeds.&lt;/p&gt;
&lt;p&gt;Embedly is in violation of section 1.4.A of the &lt;a href="https://dev.twitter.com/terms/api-terms"&gt;Twitter Terms of Service&lt;/a&gt; by resyndicating their oEmbed API response. With the release of v1.1 of their API we lost our white list status and have been using a stop gap ever since.&lt;/p&gt;
&lt;p&gt;Yesterday we got the official word that we must fall in line after a month of trying to work something out.&lt;/p&gt;
&lt;p&gt;We had a good run and a pretty good relationship with Twitter.&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;span&gt;We were white listed to make a high volume of API calls.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;We were listed as a method to embed tweets on dev.twitter.com before their official embed was released.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;span&gt;Embedly supports embedding content from over 250 different sites and this is the first time that we have ever had to remove a provider. Every other provider we have talked to views Embedly as a method of furthering their reach. More sites where there content can be shared and grow.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So, what does this mean for Embedly users?&lt;/p&gt;
&lt;p&gt;Twitter&amp;#8217;s Terms of Service does allow us to pass back the tweet id, but we have chosen not to include this in our oEmbed response. The tweet id is fundamentally useless for embedding tweets, especially when you already have the URL.&lt;/p&gt;
&lt;p&gt;If you would like to hit Twitter&amp;#8217;s oEmbed API directly, please refer to their &lt;a href="https://dev.twitter.com/docs/api/1.1/get/statuses/oembed"&gt;documentation&lt;/a&gt;. It requires oAuth authentication, so disregard the o in oEmbed.&lt;/p&gt;
&lt;p&gt;On &lt;span&gt;May 24th w&lt;/span&gt;&lt;span&gt;e will remove Twitter from our providers list, so if you use the Embedly&amp;#8217;s Wordpress Plugin you will need to update your providers list then. Other than that, things will just fail naturally.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I apologize for this one and wish we could have come to a better resolution with Twitter.&lt;/p&gt;
&lt;p&gt;The good news here is that Twitter represents only about 0.4% of URLs Embedly processes on a given day.&lt;/p&gt;
&lt;p&gt;If you have any questions or concerns you can contact me directly at sean@embed.ly.&lt;/p&gt;
&lt;p&gt;Sean&lt;/p&gt;</description><link>http://blog.embed.ly/post/48863115964</link><guid>http://blog.embed.ly/post/48863115964</guid><pubDate>Thu, 25 Apr 2013 13:33:00 -0400</pubDate><category>twitter</category><category>embed</category><dc:creator>screeley</dc:creator></item><item><title>Boston Startup Walkabout with Embedly</title><description>&lt;p&gt;&lt;span&gt;&lt;img alt="image" src="http://media.tumblr.com/2c5b37b19f6967de3c7138035fca20ea/tumblr_inline_mlrq7ptZUV1qz4rgp.png"/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Next Friday, May 3, we are opening our doors to the StartupWalkabout community for a meet and greet with our team from 11am to 1pm. Serving up lunch and some of our personal favorite brews, we&amp;#8217;re making our presence known in Boston. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.startupwalkabout.com"&gt;The Boston Startup Walkabout&lt;/a&gt; is a 4-day long city-wide event for job seekers and members of the tech community.  Over the course of the week, some of Boston&amp;#8217;s best startups will be opening their doors to network, enjoy some treats and show why you should join their team. With some great names such as TechStars, MassChallenge, and PayPal, you will be wowed by some of the opportunities these Boston startups have to offer.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re in the area and want to get to know the local startup community, looking for a job, or just want to see what we&amp;#8217;ve been up to, swing by and grab a bite. We want to get to know our neighbors too so look out for an Embedly employee at some of the walkabout events! Take a look at our &lt;a href="http://embed.ly/company/jobs"&gt;jobs page&lt;/a&gt; to get a better understanding of what we&amp;#8217;re looking for.&lt;/p&gt;
&lt;p&gt;Sign up for Embedly&amp;#8217;s event &lt;a href="http://walkaboutembedly.eventbrite.com/"&gt;here&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Final Note: Space is limited to 20, so snag your spot quick.&lt;/strong&gt;&lt;/p&gt;</description><link>http://blog.embed.ly/post/48781747258</link><guid>http://blog.embed.ly/post/48781747258</guid><pubDate>Wed, 24 Apr 2013 12:48:00 -0400</pubDate><category>ninerr</category><category>startup walkabout</category><category>techstars</category><dc:creator>ninerr</dc:creator></item><item><title>User Spotlight: Blain Smith of Adjacent Concepts</title><description>&lt;p&gt;A few days ago I came across a tweet:&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;
&lt;p&gt;Quickly embed content into @&lt;a href="https://twitter.com/statamic"&gt;statamic&lt;/a&gt; with this @&lt;a href="https://twitter.com/embedly"&gt;embedly&lt;/a&gt; plugin &lt;a href="https://t.co/LqAK3CxGQY" title="https://github.com/blainsmith/Statamic-Embedly-Plugin"&gt;github.com/blainsmith/Sta…&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;— Blain Smith (@blainsmith)&lt;/div&gt;
&lt;div&gt;&lt;a href="https://twitter.com/blainsmith/status/323872244319264768"&gt;April 15, 2013&lt;/a&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;script charset="utf-8" src="//platform.twitter.com/widgets.js" type="text/javascript"&gt;&lt;/script&gt;&lt;p&gt;&lt;span&gt;I was pretty pumped because I enjoy seeing what people can do with our API and this was a perfect example. So, I reached out to Blain with a few questions&amp;#8230;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What sorts of projects do you generally work on?&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span&gt;My projects are all over. I&amp;#8217;ve done a lot of small business websites, SaaS web apps, custom web apps, and large scale websites. Recently I joined MadGlory Interactive as a partner where we build web communities for the gaming industry. Everything from franchise websites to forums and custom leader boards of stats.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;What inspired you to create the plugin for Statamic?&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span&gt;Aside from being close friends with the creators of Statamic, I really believe in it. I also believe that in order for any new CMS to be successful it needs a really broad range of open source plugins available to extend its functionality. Embedly is a great service to extend Statamic to allow its user to easily publish media from all over the web without being technical. Embedly deserves to be a part of every CMS to make embedding easy.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;What did you like about using the API?&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span&gt;Not only is the API easy to use, the extensive list of media providers is amazing. It really makes integrating media from other sources such a seamless and uniform experience.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;What would you like to see from Embedly after working on this project or in general?&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span&gt;In general, I would love to see Embedly in the media more. I read a lot of articles on Hacker News, Smashing Magazine, and Slashdot, and other sources, but I haven&amp;#8217;t seen much from Embedly on there. Embedly really deserves a lot of recognition for the service it provides.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Wow, what encouraging words! Make sure to take a look at the &lt;a href="https://github.com/blainsmith/Statamic-Embedly-Plugin"&gt;plugin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;This post is part of &lt;a href="http://blog.embed.ly/tagged/spotlight"&gt;our spotlight series&lt;/a&gt;.  L&lt;/span&gt;&lt;span&gt;et us know what you&amp;#8217;ve created with Embedly- small project or a massive endeavor- we want to hear about it.  If you haven&amp;#8217;t tried the API yet, you can &lt;a href="http://app.embed.ly/signup"&gt;get started now&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;</description><link>http://blog.embed.ly/post/48632752645</link><guid>http://blog.embed.ly/post/48632752645</guid><pubDate>Mon, 22 Apr 2013 16:12:00 -0400</pubDate><category>plugin</category><category>spotlight</category><category>ninerr</category><category>statamic</category><dc:creator>ninerr</dc:creator></item><item><title>Encryption Project Uses Embedly Extract to Preprocess Articles</title><description>&lt;p&gt;Embedly was selected to present our APIs and offer support as an ambassador at the 2013 &lt;a href="http://hackny.org/"&gt;hackNY&lt;/a&gt;.  There was lots of energy in the room, with a focus on projects being awesome, rather than chasing hockey stick growth.  They even had a hardware hacking room with 3D printers. &lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="http://media.tumblr.com/f1c4f7bdc67eee2304acee14d3f06a2e/tumblr_inline_mlf1iibNZC1qz4rgp.png"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="http://media.tumblr.com/c461d7682144d3e7e0534662d5e57e3f/tumblr_inline_mlf1ifHMIF1qz4rgp.png"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="http://media.tumblr.com/77b36d6d471e06ff92199138a74b53ec/tumblr_inline_mlf3f9L2GB1qz4rgp.png"/&gt;&lt;/p&gt;

&lt;p&gt;One of the projects, &lt;a href="https://www.hackerleague.org/hackathons/spring-2013-hackny-student-hackathon/hacks/edison-encyption"&gt;Edison Encryption&lt;/a&gt;, used the &lt;a href="http://embed.ly/extract"&gt;Embedly Extract API&lt;/a&gt; as one of the steps for an encryption algorithm.  The team consisted of Eric Schles, Dan Cohen, Chris Williams, and Danny Padawer.&lt;/p&gt;
&lt;p&gt;Details of the algorithm are &lt;a href="https://github.com/EricSchles/Edison"&gt;provided on Github&lt;/a&gt;. &lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;span&gt;The algorithm currently adds padding to plaintext in such a way that makes cryptanalysis more difficult. This is because it pads based on a given corpus (chosen by the encrypter) and mimics that frequency. This makes discerning the true plaintext difficult. In order decrypt, you need a series of offsets, for each actual plaintext character. By combining both of these, we have an easy to decrypt and relatively cheap encryption algorithm.&lt;/span&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span&gt;When I saw the project presentation I was curious how Embedly was used in it.  Eric got back to us, mentioning that Embedly Extract was used specifically to parse an article and get the content. From Eric: &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We used embedly to get corpus&amp;#8217; of a specific kind.  We then did frequency analysis(similar to what is done in cryptanalysis) on the corpus in order to determine likely frequency patterns, making it difficult to tell which letters are part of the plaintext and which are part of the ciphertext.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;According to Eric, the team doesn&amp;#8217;t plan on stopping now, and has some pretty admirable ambitions.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We plan to expand this hack and turn it into a cryptographic standard that makes the internet a safer better place.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When we built Extract, we knew it would be used in natural language processing applications, but we never imagined it would be used for encryption.  Pretty cool seeing how people use the Extract API!&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;d like to start using Extract, you can &lt;a href="https://app.embed.ly/signup"&gt;sign up free&lt;/a&gt;, and get started with some &lt;a href="http://embed.ly/extract/demos"&gt;demos&lt;/a&gt; and &lt;a href="http://blog.embed.ly/post/46866021829/using-embedly-extract-to-find-out-whats-hot-on-reddit"&gt;tutorials&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;HackNY was a great time.  If you&amp;#8217;re having a hackathon, let us know, we&amp;#8217;d love to come by.&lt;/p&gt;
&lt;p&gt;Update (04/18/13):  Danny got back to us on what it was like using the Extract API:&lt;/p&gt;
&lt;blockquote&gt;

&lt;p&gt;We only used the extraction API, but it was very nice, easy, simple to use. It returned everything we needed.&lt;/p&gt;
&lt;p&gt;No complaints, and it worked quickly, which is always nice at a Hackathon - minimal time was needed to get it doing everything we needed.&lt;/p&gt;

&lt;/blockquote&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Great to hear!&lt;/p&gt;</description><link>http://blog.embed.ly/post/48215162717</link><guid>http://blog.embed.ly/post/48215162717</guid><pubDate>Wed, 17 Apr 2013 15:16:00 -0400</pubDate><category>extract</category><category>natural language processing</category><category>encryption</category><category>hackny</category><category>whichlight</category><dc:creator>whichlight</dc:creator></item><item><title>Ember at Embedly: Views and Controllers</title><description>&lt;p&gt;The third post in our series on Ember will continue to work from the development environment that we worked on in the &lt;a href="http://blog.embed.ly/post/46586649344/introduction-to-ember-development" title="first"&gt;first&lt;/a&gt; and &lt;a href="http://blog.embed.ly/post/47205604241/ember-at-embedly-templates-and-the-router" title="first"&gt;second&lt;/a&gt; posts.&lt;/p&gt;
&lt;p&gt;As promised last time, this post will dive into views and controllers. Here is where the magic happens. We&amp;#8217;ll also touch on models, but we&amp;#8217;ll save the bulk of the models work for our next post.&lt;/p&gt;
&lt;h3&gt;Controllers&lt;/h3&gt;
&lt;p&gt;This time let&amp;#8217;s try and fill in some details on the about page. Since it needs to be about something, let&amp;#8217;s create a fictitious organization called Jubarian. We&amp;#8217;ll create a simple controller to display information about the organization and add it to index.html.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;    // app/scripts/modules/about.js
    App.AboutController = Em.Controller.extend({
      name: 'jubarian.org',
      description: 'A non-profit organization of peopled dedicating to spreading joy.'
    });

    // app/index.html
    __snip__
    &amp;lt;script src="scripts/modules/about.js"&amp;gt;&amp;lt;/script&amp;gt;
    __snip__

    // app/templates/about.handlebars
    &amp;lt;h1&amp;gt;About {{name}}&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;{{description}}&amp;lt;/p&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This works, but it&amp;#8217;s not very MVC. We shouldn&amp;#8217;t be adding our data directly to our controller. Our controller should only contain data directly relevant to display concerns.&lt;/p&gt;
&lt;p&gt;Controllers in Ember are a little different then what you may be used to in more traditional MVC frameworks. Usually, they are implemented as proxies to a model and passed to the view using an ObjectController or ArrayController. The view will never interact with the model directly, only through the controller proxy. This allows us to have a clean separation of data concerns and display concerns. The controller decorates the model with display logic. Let&amp;#8217;s implement something to make things more clear.&lt;/p&gt;
&lt;h3&gt;ObjectController&lt;/h3&gt;
&lt;p&gt;There are two main types of controllers that are most common in Ember applications, the ObjectController and the ArrayController. In this case, we&amp;#8217;ll use an ObjectController, since there is only a single organization being displayed. We&amp;#8217;ll create a naively simple model to hold our data and connect it to the controller in the router.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;     // app/scripts/modules/about.js
     App.Fixtures = App.Fixtures || {};

     // our model
     App.Fixtures.Org = {
       name: 'jubarian.org',
       description: 'A non-profit organization of peopled dedicating to spreading joy.'
     }

     App.AboutController = Em.ObjectController.extend({})

     App.AboutRoute = Em.Route.extend({
       model: function() {
         return App.Fixtures.Org;
       }
     });
&lt;/pre&gt;
&lt;p&gt;Properties of Ember objects aren&amp;#8217;t set directly. We always use &lt;code&gt;set(name)&lt;/code&gt; and &lt;code&gt;get(name)&lt;/code&gt; functions to allow Ember to notify the objects observers of property changes. This is what allows Ember to automatically update views when properties change. Since our Org object is not an Ember object, Ember won&amp;#8217;t be able to detect changes to it. We&amp;#8217;ll cover a more robust way of doing thing in the next post, when we cover models and ember-data.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ll need to wire up our Org to the AboutController. We do this by defining a method function property on our AboutRoute object. ObjectControllers are different then a regular controller because they proxy all of their undefined properties to the object defined as their &lt;code&gt;content&lt;/code&gt; property. Ember will automatically call the model function and set the result to the &lt;code&gt;content&lt;/code&gt; property of the controller.&lt;/p&gt;
&lt;p&gt;Our controller, as it stands, doesn&amp;#8217;t do anything. Before we created it we were using an auto-generated controller of type Controller. Since it wasn&amp;#8217;t an ObjectController, it didn&amp;#8217;t proxy to the content property. Now that we&amp;#8217;ve defined it as an ObjectController, all undefined properties pass through to the content property, our org fixture.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s add some state to the display so the controller has something to do. We&amp;#8217;ll add a list of team members with a toggle for displaying or hiding it. This will also give us a chance to setup an ArrayController and see how that works. But first let&amp;#8217;s just create a static view. And modify the AboutController to handle the team display logic.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;      // app/templates/team.handlebars
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;Bob&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;Andy&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;

      // app/templates/about.handlebars
      _snip_
      &amp;lt;p&amp;gt;
        &amp;lt;a href="#" {{action toggleTeam}}&amp;gt;{{toggleTeamLabel}}&amp;lt;/a&amp;gt;
      &amp;lt;/p&amp;gt;

      {{view App.TeamView isVisibleBinding="teamVisible"}}


      // app/scripts/modules/about.js
      _snip_
      App.AboutController = Em.ObjectController.extend({
        teamVisible: false,
        toggleTeam: function() {
          this.set('teamVisible', !this.get('teamVisible'));
        },
        toggleTeamLabel: function() {
          var vis = this.get('teamVisible');
          return vis ? 'hide team' : 'show team';
        }.property('teamVisible')
      });

      App.TeamView = Em.View.extend({
        templateName: 'team'
      })
&lt;/pre&gt;
&lt;p&gt;You&amp;#8217;ll notice that we had to explicitly create the TeamView object. That is because it wasn&amp;#8217;t generated through the router so the template name isn&amp;#8217;t automatically discovered.&lt;/p&gt;
&lt;h3&gt;Properties&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;toggleTeamLabel&lt;/code&gt; is a good example of a dynamic property. When &lt;code&gt;controller.get('toggleTeamLabel')&lt;/code&gt; is called, the function will be used to generate toggleTeamLabel&amp;#8217;s value. To denote this, the &lt;code&gt;property&lt;/code&gt; function is called on the function. The property function takes a list of arguments that define it&amp;#8217;s dependencies. This is important for observers of the property, and to allow Ember to cache the property result. Ember knows that when &lt;code&gt;teamVisible&lt;/code&gt; changes, so does &lt;code&gt;toggleTeamLabel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In our &lt;code&gt;about&lt;/code&gt; template, we have created an anchor tag that fires &lt;code&gt;toggleTeam&lt;/code&gt; on AboutController whenever it is clicked using the action helper. We are using the &lt;code&gt;toggleTeamLabel&lt;/code&gt; as the display name of the tag. We use the view helper to insert the TeamView into our template. &lt;code&gt;isVisibleBinding="teamVisible"&lt;/code&gt; is a special attribute that binds the &lt;code&gt;isVisible&lt;/code&gt; attribute of TeamView to the &lt;code&gt;teamVisible&lt;/code&gt; property of the current scope, which happens to be AboutController. Now, whenever &lt;code&gt;teamVisible&lt;/code&gt; changes, so will &lt;code&gt;isVisible&lt;/code&gt;. &lt;code&gt;isVisible&lt;/code&gt; is a builtin property of every View that controls whether or not it is visible.&lt;/p&gt;
&lt;h3&gt;ArrayController&lt;/h3&gt;
&lt;p&gt;Now let&amp;#8217;s convert the static template, &lt;code&gt;team&lt;/code&gt;, into a proper ArrayController. Since we want the view to have it&amp;#8217;s own controller, and not share a controller with AboutView, we&amp;#8217;ll change it from a {{view}} to a {{render}}. This will allow us to wire up the array of team members to an ArrayController and associate it with the view.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;    // app/modules/about.js
    App.Fixtures.Team = [
      { name: 'Bob' },
      { name: 'Andy' },
      { name: 'John' },
      { name: 'Kawan' },
      { name: 'Nina' },
      { name: 'Sean' },
      { name: 'Art' },
    ];
    
    _snip_

    App.Team Controller = Em.ArrayController.extend({
      needs: 'about',
      about Binding: 'controllers.about'
    });

    App.TeamView = Em.View.extend({
      isVisibleBinding: 'controller.about.teamVisible'
    });

    // app/template/about.handlebars
    _snip_

    {{render "team" App.Fixtures.Team}}

    _snip_

    // app/templates/team.handlebars
    &amp;lt;ul&amp;gt;
      {{#each controller}}
        &amp;lt;li&amp;gt;{{name}}&amp;lt;/li&amp;gt;
      {{/each}}
    &amp;lt;/ul&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;render&lt;/code&gt; helper will automatically find the correct view and controller based on the first parameter, the template name. The second parameter will be used as the model.&lt;/p&gt;
&lt;p&gt;The way we are binding AboutController&amp;#8217;s &lt;code&gt;teamVisible&lt;/code&gt; property to TeamView is a bit contrived, but it shows how controllers can be bound together. We declare that TeamController needs AboutController and that the about property of TeamController is bound the AboutController. We then bind TeamView&amp;#8217;s &lt;code&gt;isVisible&lt;/code&gt; property to AboutController&amp;#8217;s &lt;code&gt;teamVisible&lt;/code&gt; property.&lt;/p&gt;
&lt;p&gt;Since TeamController is now an ArrayController, we can iterate over it&amp;#8217;s &lt;code&gt;content&lt;/code&gt; with the &lt;code&gt;each&lt;/code&gt; helper. &lt;code&gt;each&lt;/code&gt; will iterate over the collection putting it in scope for the contained template, in this case &lt;code&gt;&amp;lt;li&amp;gt;{{name}}&amp;lt;/li&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;With a few lines of code we&amp;#8217;ve made a dynamic, data driven about page and demonstrated the power of Ember views and controllers. You can find the source for the project on &lt;a href="https://github.com/screeley/ember-demo-environment/tree/part-3" title="github" target="_blank"&gt;github&lt;/a&gt;  This wraps up our brief intro to views and controllers. Our next blog in the series will give an introduction to ember-data, a web ORM for ember. See you next time!&lt;/p&gt;</description><link>http://blog.embed.ly/post/48039881005</link><guid>http://blog.embed.ly/post/48039881005</guid><pubDate>Mon, 15 Apr 2013 09:53:00 -0400</pubDate><category>emberjs</category><category>javascript</category><category>dokipen</category><dc:creator>dokipen</dc:creator></item><item><title>User Spotlight: FetchNotes</title><description>&lt;p&gt;&lt;span&gt;Our users are what keeps us going so we&amp;#8217;ve decided to start a weekly user spotlight series to showcase your projects and creations.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;First up is &lt;/span&gt;&lt;a href="http://www.fetchnotes.com/"&gt;Fetchnotes&lt;/a&gt;&lt;span&gt;. An app that&amp;#8217;s core mission is to make productivity as simple as a tweet. When using Fetchnotes, your tasks are grouped by hashtags, as in #todo, #email, #groceries, and #buy. As you place hashtags on each task, they are grouped by the hashtag and you can access them more clearly via your phone or dashboard. Pretty slick.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://media.tumblr.com/df589312ec94ec27603f76fbc010689f/tumblr_inline_ml3ghfWeTI1qz4rgp.png"/&gt;&lt;/p&gt;

&lt;p&gt;So, how do they use Embedly? Fetchnotes founder and CEO, Alex Schiff filled us in,&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;#8220;Embedly makes it easy for our users to act on the notes they take, so it directly supports that goal of helping people execute. When they save a YouTube link, Embedly allows them to watch it from directly within our app - no extra steps. When they save an article to read later, it previews it and gives them relevant context. It cuts down on the steps from &amp;#8220;I want to&amp;#8230;&amp;#8221; to &amp;#8220;done.&amp;#8221;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The original feature of &lt;a href="http://embed.ly/embed"&gt;Embed&lt;/a&gt; being put to use, to help you finish that growing to do list that&amp;#8217;s probably making you sick.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Last thing we&amp;#8217;d like to add is what Fetchnotes is hoping to see from us in the near future. We build for you, so when you ask us to create something we always try our best to deliver. What is Fetchnotes hoping for?&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;#8220;One thing I&amp;#8217;d love to see from Embedly is to pull in similar results without needing the link itself. So rather than needing the link to a song on Rdio to pull in the preview, it would be awesome if it could find it based off of having the artist name or song in the text.&amp;#8221;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ll be sure to add that to our &lt;em&gt;to do&lt;/em&gt; list (cleverly placed statements are my speciality, look out). Awesome to see such a dynamic app using our API and we hope to see more. Make sure to take a look at &lt;a href="http://www.fetchnotes.com"&gt;Fetchnotes&lt;/a&gt; to kickstart your productivity. And if you&amp;#8217;re using Embedly, let me know, I&amp;#8217;ll be diligently writing posts for as long as you contribute! Feel free to email me directly at nina@embed.ly.&lt;/p&gt;
&lt;p&gt;Interested in what you could create with Embed? Check it out &lt;a href="http://embed.ly/products"&gt;here&lt;/a&gt;, mosey on over to the &lt;a href="http://www.app.embed.ly/signup"&gt;sign up&lt;/a&gt; and start using Embedly for free.&lt;/p&gt;</description><link>http://blog.embed.ly/post/47625633896</link><guid>http://blog.embed.ly/post/47625633896</guid><pubDate>Wed, 10 Apr 2013 12:02:00 -0400</pubDate><category>ninerr</category><category>fetchnotes</category><category>spotlight</category><dc:creator>ninerr</dc:creator></item><item><title>Embedly at the ML/NLP Hackathon w/ Traackr and Hack/Reduce</title><description>&lt;p&gt;As you may know, we co-sponsored a hackday with &lt;a href="http://traackr.com/blog/2013/03/a-successful-elasticsearch-boston-nlpml-hackday/"&gt;Traackr&lt;/a&gt; and &lt;a href="http://www.elasticsearch.com/"&gt;Elasticsearch&lt;/a&gt; at &lt;a href="http://www.hackreduce.org/"&gt;Hack/Reduce&lt;/a&gt;.  A one-day event centered around Machine Learning and Natural Language Processing that turned out to be a hit.&lt;/p&gt;
&lt;p&gt;The event host, George Stathis of Traackr had a few favorites but one stood out to us: Alex Lambert from &lt;a href="http://spindle.com/"&gt;Spindle&lt;/a&gt;. He processed articles from the Economist from the past 5 years and rated them on 3 different mood scales from the Affective Norms for English Words (ANEW) word scores to see if indeed the world is coming to an end, no joke. Thankfully, he came to the conclusion that the world is not ending, so we are all safe&amp;#8230;for now.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Embedly’s own Andy and Art created their own “NFL coach”. This one hit close to home as many of the guys in the office, including my lady self, are pretty big NFL fans. They took 10 years worth of very detailed NFL play data and used it to train an ML algorithm to predict what play should be called. Once it was trained, they tested to see how often it made the same call as a professional coach would. The results? Out of 44 thousand plays a year in the NFL, their algorithm would give 1 out of 11 options, out of all of those options, they would get around 22 thousand right. So 50% for a bot acting like a pro football coach? Not bad.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;John and Kawan gave &lt;a href="https://docs.google.com/a/embed.ly/presentation/d/1iFhdAGv4VjaXsWdGqnnK4KpqpIF_4nrsvSzafmYKUoE/edit#slide=id.gd0afe14d_0207"&gt;a talk&lt;/a&gt; at the beginning to get the ideas going. They went in depth on how we use machine learning and NLP in-house to build some of Embedly’s features, including parts of our new product, &lt;a href="http://embed.ly/extract"&gt;Extract&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;img alt="image" src="http://media.tumblr.com/8905aa67f0d4d82a8bd634b86a447ed9/tumblr_inline_mksmzmy83I1qz4rgp.jpg"/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;The winner of the Best Use of the Embedly API was &lt;/span&gt;&lt;a href="http://www.sandsfish.com/"&gt;Sands Fish&lt;/a&gt;&lt;span&gt;. I had the pleasure of interviewing him about his project.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Sand&amp;#8217;s idea was to use a large amount of data that he had in the form of 15,000+ tweets from this year&amp;#8217;s SXSW conference and &amp;#8220;write a service to aggregate all of the tweets containing #SXSWi and #SXSWedu&amp;#8221;. He said, &amp;#8220;my main goal was to enrich the data as much as possible so I could paint a more complete picture of what happened [at the conference] and get some insight into what ideas, people, and companies were being talked about the most&amp;#8221;. Pretty nifty. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;#8220;The embedly API was a great fit…while I was only able to enrich tweets that contained links, there were more than 5,000 in this category, and for each of them, the API provided me with a wealth of data about the resources linked to in the tweet&amp;#8221;. Sands created an image-wall with the data, keeping time in mind, this was the most he felt comfortable creating. Sands mentioned that he had &amp;#8220;many ambitions for the data-set&amp;#8221; and you better believe we&amp;#8217;re excited to see what he comes up with given the luxury of time, post hackday.&lt;/span&gt;&lt;/p&gt;</description><link>http://blog.embed.ly/post/47467193605</link><guid>http://blog.embed.ly/post/47467193605</guid><pubDate>Mon, 08 Apr 2013 13:38:00 -0400</pubDate><category>ninerr</category><category>machine learning</category><category>natural language processing</category><category>hackday</category><dc:creator>ninerr</dc:creator></item><item><title>Verelo's Public Shaming</title><description>&lt;p&gt;&lt;span&gt;As reported by Pingdom, Embedly&amp;#8217;s uptime for the month of April has been 100%. We pay Pingdom to manage these checks and have configured them to properly monitor the API&amp;#8217;s health.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We were pretty surprised when Verelo started reporting on Twitter that we were down. If you have never heard of Verelo (neither had I), they monitor uptime like Pingdom and were recently acquired by Dyn.&lt;/p&gt;
&lt;p&gt;Apparently they are also into public shaming to try to drum up business, so we are going to return the favor.&lt;/p&gt;
&lt;p&gt;Verelo runs a site called &lt;a href="http://whatsdowntoday.com"&gt;whatsdowntoday.com&lt;/a&gt; where they hook up their services to a bunch of sites without notifying them first. They ping them and tweet out at &lt;a href="https://twitter.com/verelostatus"&gt;@verelostatus&lt;/a&gt; when one fails to pass it&amp;#8217;s status check.&lt;/p&gt;
&lt;p&gt;They nicely have Tweet and Facebook buttons to share downtime, but no links to the service they are actually checking.&lt;/p&gt;
&lt;p&gt;Embedly&amp;#8217;s API is one of these services, however, their check is not configured correctly. Verelo does not include an API key in the URL, so when they hit our usage limit for unauthenticated requests we throw errors. If you rely on Verlo we have been down for most of the last 2 days.&lt;/p&gt;
&lt;p&gt;Funny enough, this is their API call:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;&lt;a href="http://api.embedly.com/1/oembed?&amp;amp;maxwidth=400&amp;amp;maxheight=300&amp;amp;urls=https://t.co/04SmeCDl"&gt;http://api.embedly.com/1/oembed?&amp;amp;maxwidth=400&amp;amp;maxheight=300&amp;amp;urls=https://t.co/04SmeCDl&lt;/a&gt;&lt;/pre&gt;
&lt;p&gt;That t.co url redirects to a reddit post for their own press release: &lt;a href="https://t.co/04SmeCDl."&gt;https://t.co/04SmeCDl.&lt;/a&gt; Zero comments, whomp whomp.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m all for trying to to acquire new business, but by publicly shaming people via whatsdowntoday.com is down right dirty.&lt;/p&gt;
&lt;p&gt;Attracting customers starts with building relationships, not alienating your target market. Your viral growth hack has turned into spam, time to go back to the drawing board.&lt;/p&gt;
&lt;p&gt;If you would like to see Embedly&amp;#8217;s actual status, you can check out Pingdom: &lt;a href="http://stats.pingdom.com/q1pr2ct042w3"&gt;http://stats.pingdom.com/q1pr2ct042w3&lt;/a&gt;&lt;/p&gt;</description><link>http://blog.embed.ly/post/47456918600</link><guid>http://blog.embed.ly/post/47456918600</guid><pubDate>Mon, 08 Apr 2013 10:16:00 -0400</pubDate><category>screeley</category><dc:creator>screeley</dc:creator></item><item><title>Ember at Embedly: Templates and the Router</title><description>&lt;p&gt;This is the second post in our series on Ember. We will be building off the development environment &lt;a href="http://blog.embed.ly/post/46586649344/introduction-to-ember-development"&gt;we set up in the first post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In practice, everything is based off the router and templates. Ember handles the dynamic creation of views and controllers. You really don&amp;#8217;t need them until you start dealing with data and events.&lt;/p&gt;
&lt;p&gt;By default Ember sets up two routes for you: &lt;code&gt;application&lt;/code&gt; and &lt;code&gt;index&lt;/code&gt;. &lt;code&gt;application&lt;/code&gt; is the container for your entire application while &lt;code&gt;index&lt;/code&gt; is the route for the root of your site &amp;#8216;/&amp;#8217;. You can create the two templates for these routes in the templates directory.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ touch app/templates/application.handlebars
$ touch app/templates/index.handlebars&lt;/pre&gt;
&lt;p&gt;And for good measure we will create a global nav.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ touch app/templates/nav.handlebars&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;application&lt;/code&gt; template is a good place to create scaffolding; things that need to be on every page and also inside the scope of the application. Here is our simple &lt;code&gt;application.handlebars&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;{{ render "nav" }}
&amp;lt;div class="row"&amp;gt;
 &amp;lt;div class="large-12 columns"&amp;gt;
  {{outlet}}
 &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;
&lt;p class="p1"&gt;&lt;span&gt;We just introduced two handlebars helpers that Ember uses: &lt;/span&gt;&lt;code&gt;render&lt;/code&gt;&lt;span&gt; and &lt;/span&gt;&lt;code&gt;outlet&lt;/code&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;Handlebars helpers are a part of the Handlebars template language that is included with Ember. The &lt;code&gt;render&lt;/code&gt; and &lt;code&gt;outlet&lt;/code&gt; helpers are added by Ember.&lt;/span&gt;&lt;span&gt;&lt;br/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="p1"&gt;&lt;span&gt;About &lt;/span&gt;&lt;code&gt;render&lt;/code&gt;&lt;span&gt; from the docs:&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;Renders the named template in the current context using the singleton instance of the same-named controller.&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;render&lt;/code&gt; allows you to include one template into another. It&amp;#8217;s much like the &lt;code&gt;template&lt;/code&gt; helper, but also allows you to pass data along. In this case you could use either.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;outlet&lt;/code&gt; is a placeholder that allows you to specify where the child node&amp;#8217;s content will be rendered. They are much like &lt;code&gt;{% block %}&lt;/code&gt; tags in Django or &lt;code&gt;&amp;lt;%= yield ==%&amp;gt;&lt;/code&gt; in ERB.&lt;/p&gt;
&lt;p&gt;Since &lt;code&gt;application.handlebars&lt;/code&gt; is the base route the content from &lt;code&gt;index.handlebars&lt;/code&gt; will be rendered where this &lt;code&gt;outlet&lt;/code&gt; is. We can create a simple &lt;code&gt;index.handlebars&lt;/code&gt; to prove this.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ echo "&amp;lt;h1&amp;gt;Welcome To My App&amp;lt;/h1&amp;gt;" &amp;gt; app/templates/index.handlebars&lt;/pre&gt;
&lt;h3&gt;Routes&lt;/h3&gt;
&lt;p&gt;Routes are URL paths. To add a new page, you need to add a new route. So to add our about page, we need to add a route to our router.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;App.Router.map(function(){
  this.route('about');
});&lt;/pre&gt;
&lt;p&gt;Ember is creating &lt;code&gt;AboutRoute&lt;/code&gt;, &lt;code&gt;AboutView&lt;/code&gt;, and &lt;code&gt;AboutController&lt;/code&gt;. We don&amp;#8217;t really need those for this exercise, but we do need a template with some content.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ echo "&amp;lt;h1&amp;gt;About To My App&amp;lt;/h1&amp;gt;" &amp;gt; app/templates/about.handlebars&lt;/pre&gt;
&lt;p&gt;If you visit &amp;#8216;/#/about&amp;#8217; you will see the content.&lt;/p&gt;
&lt;h3&gt;Resources&lt;/h3&gt;
&lt;p&gt;When you want to start grouping routes, i.e. &amp;#8220;/company/contact&amp;#8221; and &amp;#8220;/company/team&amp;#8221; resources come in to play. The benefit here is that they share common templates. While you could so something like this:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;App.Router.map(function(){
  this.route('contact', {path:'/company/contact'});
  this.route('team', {path:'/company/team'});
});&lt;/pre&gt;
&lt;p&gt;It becomes a mess really quickly. Instead you should use a resource.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;App.Router.map(function(){
  this.resource('company', function(){
    this.route('contact');
    this.route('team');
  });
});&lt;/pre&gt;
&lt;p&gt;It is however a little more confusing when it comes to templates. Like the application route, we need to create a base container for all the leaf routes. This could be as simple as:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ echo "{{outlet}}" &amp;gt; app/templates/company.handlebars&lt;/pre&gt;
&lt;p&gt;In this case, everything will just be added to the outlet in the &lt;code&gt;application.handlebars&lt;/code&gt;. If you want every company page to have common display attributes, you can change the template:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;&amp;lt;h1&amp;gt;Company&amp;lt;/h1&amp;gt;
&amp;lt;div class="row"&amp;gt;
  &amp;lt;div class="large-9 columns"&amp;gt;
    {{outlet}}
  &amp;lt;/div&amp;gt;
  &amp;lt;div id="sidebar" class="large-3 columns"&amp;gt;
    {{outlet sidebar}}
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;
&lt;p&gt;You&amp;#8217;ll notice here that we added a named outlet. By default all content from the leaf routes will go into the &lt;code&gt;{{outlet}}&lt;/code&gt; unless we tell it to go somewhere else instead.&lt;/p&gt;
&lt;p&gt;We can then create the leaf templates.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ mkdir app/templates/company
$ touch app/templates/company/index.html
$ touch app/templates/company/contact.html
$ touch app/templates/company/team.html&lt;/pre&gt;
&lt;p&gt;This is one of the nice things about having &lt;code&gt;ember_templates&lt;/code&gt; set up and compiling templates for you. Ember expects the templates to be put into EM.TEMPLATES hash as &amp;#8216;resource/route&amp;#8217; or you need to declare the templateName on the view. The former is less code.&lt;/p&gt;
&lt;h3&gt;Custom Routes&lt;/h3&gt;
&lt;p&gt;We set up that outlet earlier, it&amp;#8217;s time that we use it. In order to use named outlets we need to modify the Routes behavior. Here we will change that Company Team Route to add a sidebar. In the main.js file we are going to add:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;App.CompanyTeamRoute = Em.Route.extend({
  renderTemplate: function(controller, model){
    // Render the base template
    this._super(controller, model);
    // Render the bios template into the sidebar
    this.render('bios', {outlet: 'sidebar'});
  }
});&lt;/pre&gt;
&lt;p&gt;And then add the bios template:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ echo "&amp;lt;h2&amp;gt;Bios&amp;lt;/h2&amp;gt;" &amp;gt; app/templates/bios.handlebars&lt;/pre&gt;
&lt;p&gt;When you visit /#/company/team you will see the bios section in the template.&lt;/p&gt;
&lt;p&gt;Alright, that was a quick primer into the Router and Templates, you can see the final code here: &lt;a href="https://github.com/screeley/ember-demo-environment/tree/router."&gt;https://github.com/screeley/ember-demo-environment/tree/router.&lt;/a&gt; Next week, we&amp;#8217;ll go into using View and Controllers.&lt;/p&gt;</description><link>http://blog.embed.ly/post/47205604241</link><guid>http://blog.embed.ly/post/47205604241</guid><pubDate>Fri, 05 Apr 2013 14:19:00 -0400</pubDate><category>emberjs</category><category>screeley</category><category>javascript</category><dc:creator>screeley</dc:creator></item><item><title>Using Embedly Extract to Find Out What's Hot on Reddit</title><description>&lt;p&gt;Hello there embedders! You might have noticed that we have recently released &lt;a href="http://embed.ly/products"&gt;a couple new products&lt;/a&gt; &amp;#8212; today we&amp;#8217;re going to talk about a couple features of the new /1/extract endpoint. Extract is great when you want to not only embed a URL but get a deeper understanding of its contents.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s write up a quick application that scrapes the front page of any given subreddit and uses the extract endpoint to see what people are talking about by totaling all keywords and entities. Keywords are probably what you expect them to be, while entities are essentially just proper nouns. Note that you&amp;#8217;ll need an Embedly API key to run this demo &amp;#8212; you can &lt;a href="https://app.embed.ly/signup" title="get one for free" target="_blank"&gt;get one for free&lt;/a&gt; if you don&amp;#8217;t already have one!&lt;/p&gt;
&lt;p&gt;First thing&amp;#8217;s first: let&amp;#8217;s grab the frontpage of a subreddit using reddit&amp;#8217;s awesome JSON API. This is just a simple HTTP request to the subreddit frontpage with .json appended to the URL.  We also define a function to extract all of the URLs from this blob:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;import sys
import json
import urllib

import requests

def reddit(sub):
    """
    Retrieve the json representation of the given subreddit
    """
    url = 'http://reddit.com/r/%s.json' % sub
    resp = requests.get(url)
    return json.loads(resp.text)

def reddit_urls(js):
    """
    Return all the URLs in the given json blob of reddit data
    """
    return [x['data']['url'] for x in js['data']['children']]
&lt;/pre&gt;
&lt;p&gt;The above code depends on one external package: the excellent requests package, which makes performing HTTP requests very simple.&lt;/p&gt;
&lt;p&gt;Now that we have a list of URLs, let&amp;#8217;s call embedly&amp;#8217;s extract endpoint. For URLs that have any significant amount of text this response will include keywords and entites that summarize the text (take a look at an &lt;a href="https://gist.github.com/JohnEmhoff/5287109" title="example response" target="_blank"&gt;example response&lt;/a&gt; if you&amp;#8217;d like to see what else is returned).&lt;/p&gt;
&lt;pre class="prettyprint"&gt;def embedly(url, key):
    """
    Call the embedly API and return the json blob. Returns None if there
    is an error processing the URL (e.g., HTTP 404)
    """
    quoted = urllib.quote(url)
    api = 'http://api.embed.ly/1/extract?url=%s&amp;amp;key=%s' % (quoted, key)
    resp = requests.get(api)
    if resp.status_code != 200:
        sys.stderr.write('Failed to process URL %s :(\n' % url)
        return None
    return json.loads(resp.text)
&lt;/pre&gt;
&lt;p&gt;Okay, now we can just loop over all of the responses and sum together all of the counts and take the, say, ten highest counts. The code below operates on entities, but by changing &amp;#8216;entities&amp;#8217; to &amp;#8216;keywords&amp;#8217; in the line above sum_counts you can have it look at keywords instead!&lt;/p&gt;
&lt;pre class="prettyprint"&gt;def sum_counts(item_lists):
    """
    Takes a list of lists of items and mashes them all together into a dict
    mapping item_name -&amp;gt; item_score. The input items are either entity or
    keyword lists, which look like {'name': 'Dennis', 'count': 10} or
    {'name': 'sports', 'score': 33}, respectively.
    """
    ret = {}
    for item_list in item_lists:
        for item in item_list:
            # get either score or count so we can work with both
            # keywords and entities
            name, count = item['name'], item.get('count', item.get('score', 0))
            ret[name] = ret.get(name, 0) + count
    return ret

def top_n(item_dict, n):
    by_count = sorted(item_dict.iteritems(), key=lambda x: x[1],
        reverse=True)
    return by_count[:n]


def main(subreddit, key):
    urls = reddit_urls(reddit(subreddit))
    embeds = [embedly(url, key) for url in urls]
    # change 'entities' to 'keywords' to check out the keyword extraction!
    items = [x['entities'] for x in embeds if x]
    all_counts = sum_counts(items)

    top = top_n(all_counts, 10)
    print '\n'.join('%s %s' % (x[0], x[1]) for x in top)


if __name__ == '__main__':
    if len(sys.argv) &amp;lt; 3:
        sys.stderr.write('Usage: demo.py &amp;lt;subreddit&amp;gt; &amp;lt;your-embedly-key&amp;gt;\n')
    else:
        main(sys.argv[1], sys.argv[2])
&lt;/pre&gt;
&lt;p&gt;Let&amp;#8217;s try it out on /r/sports!&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ python demo.py sports &amp;lt;your-embedly-key&amp;gt;
NCAA 13
Ware 3
Sharks 2
Daily Caller 2
Kevin Ware 2
Louisville 2
Cal 2
Taylor Branch 1
San Jose Sharks 1
National Collegiate Players Association 1
&lt;/pre&gt;
&lt;p&gt;Here we can see that the NCAA is by far the most popular entity mentioned, which should be no surprise considering we&amp;#8217;re in the height of the March Madness tournament. Kevin Ware also makes an appearance, no doubt due to his unfortunate injury in Sunday&amp;#8217;s game.&lt;/p&gt;
&lt;p&gt;How about /r/worldnews?&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ python demo.py worldnews &amp;lt;your-embedly-key&amp;gt;
North Korea 66
India 30
Pakistan 27
U.S. 21
China 19
UN 17
Bolkovac 16
United States 14
EU 13
Novartis 13
&lt;/pre&gt;
&lt;p&gt;Looks like North Korea is big right now, which isn&amp;#8217;t too surprising considering what&amp;#8217;s been going on over there.&lt;/p&gt;
&lt;p&gt;Go grab the &lt;a href="https://gist.github.com/JohnEmhoff/5287169" title="source"&gt;source&lt;/a&gt; if you&amp;#8217;d like to play around. There are all sorts of ways to extend this &amp;#8212; extract also pulls image metadata, so maybe you could make an image wall sorted by keyword or entity of what&amp;#8217;s going on right now. Or use the related article feature to curate content on the current hottest topic. Speaking of related articles, we&amp;#8217;ll be showcasing that feature in an upcoming post!&lt;/p&gt;

&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;a href="https://app.embed.ly/signup" target="_blank"&gt;Sign up for a free account&lt;/a&gt;&lt;span&gt; to start using Extract and run this example, or check out the &lt;/span&gt;&lt;a href="http://embed.ly/extract" target="_blank"&gt;other features and demos available&lt;/a&gt;&lt;span&gt; for Extract.  Other thoughts? Continue the conversation on &lt;/span&gt;&lt;a href="http://twitter.com/embedly" target="_blank"&gt;Twitter&lt;/a&gt;&lt;span&gt;&lt;br/&gt;&lt;/span&gt;&lt;/p&gt;</description><link>http://blog.embed.ly/post/46866021829</link><guid>http://blog.embed.ly/post/46866021829</guid><pubDate>Mon, 01 Apr 2013 14:51:00 -0400</pubDate><category>natural language processing</category><category>nlp</category><category>machine learning</category><category>extract</category><category>tutorial</category><category>reddit</category><category>python</category><category>entities</category><category>keywords</category><category>thejohnnest</category><dc:creator>thejohnnest</dc:creator></item><item><title>In Support of John</title><description>&lt;p&gt;This is John.&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="http://media.tumblr.com/dce3a8dc5fe4e657e731b0ec351d9c7e/tumblr_inline_mkkwqcH81V1qz4rgp.jpg"/&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;John works at Embedly and he&lt;/span&gt; seems like a normal guy. He likes ultimate Frisbee, a good joke and time with friends. He has 10 fingers and 10 toes, but John was born with a great affliction. From the second he was put on this earth he had to endure overwhelming odds against him. &lt;/p&gt;
&lt;p&gt;You see when John was delivered the doctor held him up, as Rafiki did to Simba, and proclaimed &amp;#8220;April Fools.&amp;#8221; Yes, John was born on the 1st of April.&lt;/p&gt;
&lt;p&gt;Gasp, I know. Let that sink in for a second.&lt;/p&gt;
&lt;p&gt;Like millions of &amp;#8220;Foolies&amp;#8221;, as they call themselves, he was subjected to a childhood of bad jokes. &amp;#8220;Your parents must of thought you were a joke&amp;#8230;&amp;#8221; &amp;#8220;Here little Johnnie, I got you the TMNT action figure you wanted. Nope, Ha, April Fools.&amp;#8221; &amp;#8220;John, we got you a car for your Birthday. Ha, April Fools, here&amp;#8217;s a Frisbee.&amp;#8221; &amp;#8220;John, you were adopted&amp;#8230; April Fools!&amp;#8221; The courage that it takes, I can&amp;#8217;t imagine.&lt;/p&gt;
&lt;p&gt;The Foolies are a fellowship. Once a year, while everyone is out pranking they meet at a bar. They drink raspberry beer and not a single giggle is heard. They sit in peace as the world burns around them.&lt;/p&gt;
&lt;p&gt;We at Embedly support the Foolies. We will not be participating in what tech has deemed a day of bad jokes thought up by insensitive marketing people to show their company has a &amp;#8220;fun side.&amp;#8221; It hurts real people like John and we cannot condone such actions.&lt;/p&gt;
&lt;p&gt;There will be no scratch and sniff embeds and you will not be hearing Rick Astley.&lt;/p&gt;
&lt;p&gt;Instead we will be silent in solemn solace with those less fortunate than us. John, we will not be pranking anyone today, we love you, stay strong.&lt;/p&gt;
&lt;p&gt;- &lt;a href="http://twitter.com/screeley"&gt;Sean&lt;/a&gt;&lt;/p&gt;</description><link>http://blog.embed.ly/post/46846026210</link><guid>http://blog.embed.ly/post/46846026210</guid><pubDate>Mon, 01 Apr 2013 09:43:00 -0400</pubDate><category>screeley</category><dc:creator>screeley</dc:creator></item><item><title>Ember at Embedly: Introduction to Ember Development</title><description>&lt;p&gt;Every time I see Ember on Hacker News it&amp;#8217;s being trashed, like MongoDB trashed. It sucks for an open source project when the herd mentality kicks in and it becomes cool to hate. Sadly, I&amp;#8217;m not one of the cool kids.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://emberjs.com"&gt;Ember&lt;/a&gt; is excellent. We use it extensively here at Embedly for our developer dashboard. While none of us here are JavaScript experts, Ember has made us incredibly productive.&lt;/p&gt;
&lt;p&gt;We are going to do a series of posts on Ember at Embedly. Mostly tips and tricks that have made us successful. These are not aimed at the pro, but the amateur.&lt;/p&gt;
&lt;p&gt;A lot goes in to baking a production-quality website, and Ember adds to that. As a result, there is a lot of boilerplate when it comes to setting up the development environment. Rest assured that once you fight through the boilerplate, you&amp;#8217;ll be able to iterate at an impressive rate.&lt;/p&gt;
&lt;p&gt;Okay, so you have a new awesome idea of what you are going to build, how do you get started?&lt;/p&gt;
&lt;h3&gt;Yeoman/Grunt&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://gruntjs.com"&gt;Grunt&lt;/a&gt; is the Javascript Task Runner. It makes the set up of common tools like jshint, compass, uglify and development servers dead simple. We use it in almost every project now and it has made development a whole lot easier.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://yeoman.io"&gt;Yeoman&lt;/a&gt; is a thin wrapper around Grunt that really just builds out a directory structure and a few files. One member of your team will use it once and never think about it again.&lt;/p&gt;
&lt;p&gt;So, let&amp;#8217;s get started.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ mkdir demo
$ cd demo
$ npm install -g yo grunt-cli bower
&lt;/pre&gt;
&lt;p&gt;At the time of writing, the ember generator for yeoman is hosed, so you can do what you wish with that information. We can just use the default webapp generator.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ yo webapp
$ npm install &amp;amp; bower install
&lt;/pre&gt;
&lt;p&gt;This will build a pretty simple directory structure.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;  app /
    index.html
    scripts/
      main.js
    styles/
      main.css
  Gruntfile.js
  package.json
  test /
&lt;/pre&gt;
&lt;p&gt;Yeoman sets up the project so it can immediately be used. Run grunt&amp;#8217;s server to launch your new web app.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ grunt server
&lt;/pre&gt;
&lt;p&gt;Tada, a browser will open to http://localhost:9000/ and show a nice little Allo message.&lt;/p&gt;
&lt;h3&gt;Getting Ember&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://twitter.github.com/bower/"&gt;Bower&lt;/a&gt; is Twitter&amp;#8217;s package management tool for the Web. Let&amp;#8217;s get Ember installed using bower.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ bower install ember
&lt;/pre&gt;
&lt;p&gt;Bower will handle getting all the right dependencies and install them in a components directory. You will then need to add Ember and Handlebars to your index.html file.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ vim app/index.html
&lt;/pre&gt;
&lt;p&gt;You can put the following lines near the bottom but above main.js:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;&amp;lt;script src="components/handlebars/handlebars.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src="components/ember/ember.js"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Grunt will live reload your browser. You now have all the dependencies for a simple Ember app. You can prove it by opening up the console and running &lt;code&gt;Em&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To recap, that was about 5 commands to get Ember completely ready to go:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ npm install -g yo grunt-cli bower
$ yo webapp
$ npm install &amp;amp;&amp;amp; bower install
$ bower install ember
$ vim app/index.html
&lt;/pre&gt;
&lt;p&gt;If you complain about how hard Ember is to set up you are using the wrong tools.&lt;/p&gt;
&lt;h3&gt;Templates&lt;/h3&gt;
&lt;p&gt;Here on out is optional, but will probably save you some headaches later down the road. We will set up &lt;code&gt;grunt-ember-templates&lt;/code&gt;, an Application and the Router.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/dgeb/grunt-ember-templates"&gt;&lt;code&gt;grunt-ember-templates&lt;/code&gt;&lt;/a&gt; module pre-compiles all your templates on the fly and adds them to Em.Templates, which is where Ember keeps your templates so it can match them to your views, based on naming convention. More on this later.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ npm install grunt-ember-templates --save-dev
# Create the templates directory.
$ mkdir app/templates
$ touch app/templates/index.handlebars
&lt;/pre&gt;
&lt;p&gt;We are going to have to update the Gruntfile to run &lt;code&gt;ember_templates&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Grunt is configured by a Gruntfile.js, which uses JSON to define a bunch of different actions that Grunt can perform for you. This is where we&amp;#8217;ll hook up grunt-ember-templates to Grunt.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ vim Gruntfile.js
&lt;/pre&gt;
&lt;p&gt;In the Gruntfile, you are going to load the task before, I generally put it before the &lt;code&gt;grunt.initConfig&lt;/code&gt;&lt;/p&gt;
&lt;pre class="prettyprint"&gt;grunt.loadNpmTasks('grunt-ember-templates');
&lt;/pre&gt;
&lt;p&gt;Inside the &lt;code&gt;grunt.initConfig&lt;/code&gt; you will need to set up the compile task to point at all the templates.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;ember_templates: {
  compile: {
    options: {
      templateName: function(sourceFile) {
        return sourceFile.replace(/app\/templates\//, '');
      }
    },
    files: {
      "&amp;lt;%= yeoman.app %&amp;gt;/scripts/templates.js": ["&amp;lt;%= yeoman.app %&amp;gt;/templates/**/*.handlebars"]
    }
  }
},
&lt;/pre&gt;
&lt;p&gt;Next tell the watch command to look for changes in the templates directory to make the live reload work correctly:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;watch {
  ...
  ember_templates: {
      files: '&amp;lt;%= yeoman.app %&amp;gt;/templates/**/*.handlebars',
      tasks: ['ember_templates']
  },
  ...
}
&lt;/pre&gt;
&lt;p&gt;Lastly, add &lt;code&gt;ember_templates&lt;/code&gt; to the server task, you are looking for this line:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;grunt.registerTask('server', function (target) {
    ...
    grunt.task.run([
        ...
        'compass:server',
        'ember_templates', // Add this line.
        'livereload-start',
        ...
    ]);
});
&lt;/pre&gt;
&lt;p&gt;Once you restart grunt server, you can take a gander at the app/scripts/templates.js file in scripts. It should look something like this:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;Ember.TEMPLATES["index"] = Ember.Handlebars.template
...
&lt;/pre&gt;
&lt;p&gt;Add that script to the index.html file to make sure the browser loads it.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;&amp;lt;script src="scripts/templates.js"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;p&gt;That was kind of a detour, you don&amp;#8217;t really need to set up &lt;code&gt;ember_templates&lt;/code&gt;, you can use inline script tags or Em.Handlebars.compile, but this method offers a nice separation of HTML and javascript. For a quick reference you can see the completed Gruntfile &lt;a href="https://github.com/screeley/ember-demo-environment/blob/master/Gruntfile.js"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Application&lt;/h3&gt;
&lt;p&gt;The last step here will be to set up a simple App and Router to take advantage of our setup.&lt;/p&gt;
&lt;p&gt;You can add the main.js to the end of index.html and delete whatever is in that file.&lt;/p&gt;
&lt;pre class="prettyprint"&gt;&amp;lt;script src="scripts/main.js"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Next set up a &lt;code&gt;rootElement&lt;/code&gt; for Ember to use, this will make sure that Ember puts the html where you want it to. Replace the div with the class container with:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;&amp;lt;div id="app"&amp;gt;&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Next add a simple Application to main.js:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;App = Em.Application.create({
  rootElement: $('#app'),
});
&lt;/pre&gt;
&lt;p&gt;You can then edit index.handlebars with a simple h1&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ echo "&amp;lt;h1&amp;gt;My App&amp;lt;/h1&amp;gt;" &amp;gt; app/templates/index.handlebars
&lt;/pre&gt;
&lt;p&gt;When grunt reloads the server, your browser will have My App as the header. There is a little magic going on here. Ember is creating a Router for you and by default creates and Application Route and an Index Route. This is why just adding an index.handlebars works.&lt;/p&gt;
&lt;p&gt;The Router is dead simple to set up as well. In main.js add&lt;/p&gt;
&lt;pre class="prettyprint"&gt;App.Router.map(function(){
  this.route('about');
});
&lt;/pre&gt;
&lt;p&gt;And then create the about template&lt;/p&gt;
&lt;pre class="prettyprint"&gt;$ echo "&amp;lt;h1&amp;gt;About&amp;lt;/h1&amp;gt;" &amp;gt; app/templates/about.handlebars
&lt;/pre&gt;
&lt;p&gt;If you navigate to /#/about, boom, you are now in the About route. You can also link to the about page from index by adding:&lt;/p&gt;
&lt;pre class="prettyprint"&gt;{{#linkTo "about"}}About{{/linkTo}}
&lt;/pre&gt;
&lt;p&gt;This all works based on naming conventions. You can create an AboutController, AboutRoute and AboutView, but Ember will take care of that for these simple routes. More on that later.&lt;/p&gt;
&lt;h3&gt;Recap&lt;/h3&gt;
&lt;p&gt;Setting up Ember is a lot of boiler plate code, and there are some really good tools out there that do it for you. Nothing I have described above is earth shattering, but it should get you set up for your next Ember project.&lt;/p&gt;
&lt;p&gt;I put the complete demo on Github for reference you can find it at &lt;a href="https://github.com/screeley/ember-demo-environment"&gt;github.com/screeley/ember-demo-environment&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For our next post in the Ember series, we will go into &lt;a href="http://blog.embed.ly/post/47205604241/ember-at-embedly-templates-and-the-router"&gt;Ember basics; Views, Routing and Outlets&lt;/a&gt;. Stay tuned.&lt;/p&gt;
&lt;p&gt;- &lt;a href="http://twitter.com/screeley"&gt;Sean&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=5461296"&gt;Discuss on Hacker News&lt;/a&gt;&lt;/p&gt;</description><link>http://blog.embed.ly/post/46586649344</link><guid>http://blog.embed.ly/post/46586649344</guid><pubDate>Fri, 29 Mar 2013 11:47:00 -0400</pubDate><category>ember</category><category>emberjs</category><category>javascript</category><category>tutorial</category><category>grunt</category><category>yeoman</category><category>boilerplate</category><category>screeley</category><dc:creator>screeley</dc:creator></item></channel></rss>
