Pinboard (moonhouse)
https://pinboard.in/u:moonhouse/public/
recent bookmarks from moonhouse (from google)RX-7 / RX-8 Rotary Engine Rotor Keychain by ROBK6362011-11-04T17:05:37+00:00
http://www.makerbot.com/blog/2011/11/04/rx-7-rx-8-rotary-engine-rotor-keychain-by-robk636/
moonhouseThingalert Thingiverse Things_We_Like ROBK636 sirmakesalothttps://pinboard.in/u:moonhouse/b:41203c7f06e2/Biljettkontrollanter kände inte till Resplustillägg2011-11-01T11:33:12+00:00
http://arskortguldsj.wordpress.com/2011/11/01/biljettkontrollanter-knde-inte-till-resplustillgg/
moonhouseresplus sj årskort kollektivtrafikhttps://pinboard.in/u:moonhouse/b:3e9e09ebf2e8/Arduino controlled four socket outlet2011-10-31T18:34:48+00:00
http://hackaday.com/2011/10/31/arduino-controlled-four-socket-outlet/
moonhousehttps://pinboard.in/u:moonhouse/b:733d4c3e5bcc/Cordon multi-target photo-radar system leaves no car untagged (video)2011-10-31T13:37:00+00:00
http://www.engadget.com/2011/10/31/cordon-multi-target-photo-radar-system-leaves-no-car-untagged-v/
moonhousecamera car cars cordon gps image law license_plate license_plate_recognition LicensePlate LicensePlateRecognition photo photo_radar PhotoRadar police radar road roadway simicon speed speeding tracking vehicle videohttps://pinboard.in/u:moonhouse/b:163c299ef315/"it becomes beautiful later..."2011-10-31T03:07:17+00:00
http://kottke.org/11/10/it-becomes-beautiful-later
moonhousehttps://pinboard.in/u:moonhouse/b:d48789c1e8f3/My dad taught me cashflow with a soda machine2011-10-30T21:40:37+00:00
http://blog.thestartuptoolkit.com/2011/10/my-dad-taught-me-cashflow-with-a-soda-machine/
moonhousehttps://pinboard.in/u:moonhouse/b:8b085ff46c7c/Some responses to the magazine counterarguments2011-10-30T21:37:43+00:00
http://www.marco.org/2011/10/29/double-dipping-response
moonhousehttps://pinboard.in/u:moonhouse/b:2aaab1eccd91/Tiny robot rides tiny bike. World rejoices.2011-10-30T21:35:43+00:00
http://www.buildlounge.com/2011/10/30/tiny-robot-rides-tiny-bike-world-rejoices/
moonhousehttps://pinboard.in/u:moonhouse/b:ddec237687c1/Boys, Girls, and the HPV Vaccine2011-10-30T21:24:09+00:00
http://www.newyorker.com/online/blogs/closeread/2011/10/boys-girls-and-the-hpv-vaccine.html
moonhousehttps://pinboard.in/u:moonhouse/b:cc138d098968/Apple buys insane 3D mapping company C3 Technologies2011-10-30T08:49:16+00:00
http://www.macgasm.net/2011/10/29/apple-buys-c3-technologies/
moonhousehttps://pinboard.in/u:moonhouse/b:0d88d15b3074/40% of Canadians Will Die At Some Point In Their Lives2011-10-30T08:43:56+00:00
http://www.flickr.com/photos/tedseverson/6293147336/in/set-72157627697519411/
moonhousehttps://pinboard.in/u:moonhouse/b:47ca7c7df82a/http://i.imgur.com/B7AL9.jpg2011-10-30T08:31:23+00:00
http://i.imgur.com/B7AL9.jpg
moonhousehttps://pinboard.in/u:moonhouse/b:7914496d0deb/A FREE PHP StackOverflow Clone2011-10-29T21:37:29+00:00
http://www.coordino.com/
moonhousehttps://pinboard.in/u:moonhouse/b:b1ba4885547b/Apple Lossless Audio Codec2011-10-29T21:33:56+00:00
http://alac.macosforge.org/
moonhousehttps://pinboard.in/u:moonhouse/b:eeecff9dcff6/Foundation: Rapid Prototyping and Building Framework from ZURB2011-10-28T20:14:07+00:00
http://foundation.zurb.com/
moonhousehttps://pinboard.in/u:moonhouse/b:5355e824c553/Minimalist DIODER hack requires no external microcontroller2011-10-28T20:09:30+00:00
http://hackaday.com/2011/10/25/minimalist-dioder-hack-requires-no-external-microcontroller/
moonhousehttps://pinboard.in/u:moonhouse/b:dc8298493ec2/DIY thermostat keeps the harsh winter cold at bay2011-10-28T20:06:02+00:00
http://hackaday.com/2011/10/27/diy-thermostat-keeps-the-harsh-winter-cold-at-bay/
moonhousehttps://pinboard.in/u:moonhouse/b:1c189521796d/Android Orphans: Visualizing a Sad History of Support2011-10-28T20:03:11+00:00
http://theunderstatement.com/post/11982112928/android-orphans-visualizing-a-sad-history-of-support
moonhousehttps://pinboard.in/u:moonhouse/b:0633cca19729/Tru.ly releases its free age verification API2011-10-28T19:22:57+00:00
http://thenextweb.com/apps/2011/10/28/tru-ly-releases-its-free-age-verification-api/
moonhousehttps://pinboard.in/u:moonhouse/b:b63ea36794cb/Eva RÃ¥berg's Photo2011-10-28T19:21:19+00:00
http://lockerz.com/s/151063628
moonhousehttps://pinboard.in/u:moonhouse/b:ac2b0b407558/Labscam2011-10-22T22:32:56+00:00
http://cm.bell-labs.com/who/dmr/labscam.html
moonhousehttps://pinboard.in/u:moonhouse/b:26873f94e760/GitHub Secrets - GitHub2011-10-22T22:04:00+00:00
https://github.com/blog/967-github-secrets
moonhousehttps://pinboard.in/u:moonhouse/b:a8124a9a889c/Add search, sort and flexibility to plain HTML lists with cross-browser native JavaScript by @javve2011-10-22T21:57:49+00:00
http://listjs.com/
moonhousehttps://pinboard.in/u:moonhouse/b:b5cbaf8c9730/RubyMonk - Home2011-10-22T21:56:55+00:00
http://rubymonk.com/
moonhousehttps://pinboard.in/u:moonhouse/b:a2bab48b7f04/Tangle: a JavaScript library for reactive documents2011-10-22T21:53:39+00:00
http://worrydream.com/Tangle/
moonhouse cookies,you consume calories.And this is the JavaScript.var tangle = new Tangle(document, { initialize: function () { this.cookies = 3; }, update: function () { this.calories = this.cookies * 50; }});Write your document with HTML and CSS, as you normally would. Use special HTML attributes to indicate variables. Write a little JavaScript to specify how your variables are calculated. Tangle ties it all together.Try out some examples.Below is a simplified digital adaptation of the analog state variable filter.This topology is particularly useful for embedded audio processing, â¦
]]>https://pinboard.in/u:moonhouse/b:a67148326902/Signs that you are a bad programmer2011-10-22T21:52:52+00:00
http://badprogrammer.infogami.com/
moonhousehttps://pinboard.in/u:moonhouse/b:791443c2a563/What Rubyâs ||= (Double Pipe / Or Equals) Really Does2011-10-18T01:37:41+00:00
http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html
moonhouse 20
In this case, a ||= b seems to behave like a = a || b. As mentioned earlier, this is entirely due to a and b both being local variables.
Full Demonstration for Hashes and Arrays
Let's try something more complicated:
h = {}
def h.[]=(k, v)
puts "Setting hash key #{k} with #{v.inspect}"
super
end
# 1. The standard ||= approach
h[:x] ||= 10
h[:x] ||= 20
# 2. The a = a || b approach
h[:y] = h[:y] || 10
h[:y] = h[:y] || 20
# 3. The a || a = b approach
h[:z] || h[:z] = 10
h[:z] || h[:z] = 20
The output:
Setting hash key x with 10
Setting hash key y with 10
Setting hash key y with 10
Setting hash key z with 10
Note that in the first case, using ||=, the hash key's value is only set once. Once it becomes logically truthful (i.e. anything other than nil or false), h[:x] is no longer assigned any new values, not even itself.
The second case, using the a = a || b approach, does result in two assignments (of the same value). The value remains 10 but the syntax forces h[:y] to assign itself as a value again.
In the last case, the behavior is the same as in the first case, demonstrating that a || a = b is a more realistic notation.
Note: Exactly the same result occurs if we switch the hash for an array and the keys for integers.
Full Demonstration for Getter/Setter Methods
A similar outcome occurs if we're referring to objects with getter/setter methods (which you may call accessors):
class MyClass
attr_reader :val
def val=(val)
puts "Setting val to #{val.inspect}"
@val = val
end
end
# 1. The standard ||= approach
obj = MyClass.new
obj.val ||= 'a'
obj.val ||= 'b'
# 2. The a = a || b approach
obj = MyClass.new
obj.val = obj.val || 'c'
obj.val = obj.val || 'd'
# 3. The a || a = b approach
obj = MyClass.new
obj.val || obj.val = 'e'
obj.val || obj.val = 'f'
And the output shows off similar behavior to the hash and array example:
Setting val to "a"
Setting val to "c"
Setting val to "c"
Setting val to "e"
Default Hash Values: A Sneaky Edge Case?
Our travels don't end there though. Back in 2008, David Black noticed an edge case with hashes that have default values. If you follow the logic above to the letter, this case will not surprise you, although from a pragmatic point of view, it's curious.
Let's take a look:
hsh = Hash.new('default')
hsh[:x] # => 'default'
# 1. The standard ||= approach
hsh[:x] ||= 10
p hsh # => {}
# 2. The a = a || b approach
hsh[:y] = hsh[:y] || 10
p hsh # {:y=>"default"}
# 3. The a || a = b approach
hsh[:z] || hsh[:z] = 10
p hsh # {:y=>"default"}
Hashes with default values act in an.. interesting way, depending on your point of view. Merely accessing a value doesn't mean that the value is reified (made concrete) in the hash itself. The reason for this is that you can assign Procs to a hash's default_proc in order to perform calculations (or even to set values) when an unset key is accessed. It would be undesirable to avoid this behavior merely because a key was accessed earlier on.
Again, we note that the a || a = b-style approach gives the result closest to the reality of ||=.
describe "Conditional operator assignment 'obj.meth op= expr'" do
it "is equivalent to 'obj.meth op obj.meth = expr'" do
RubySpec's variables_spec file
Undefined Variables: Another Tricky Case
In the comments for this post, Vikrant Chaudhary brought up another interesting case:
If a is not defined, a || a = 42 raises NameError, while a ||= 42 returns 42. So, they don't seem to be equivalent expressions.
Vikrant Chaudhary
It's lucky I said "behaves like" earlier - phew! But joking aside, Vikrant makes a good point.
This tricky case is a little like the hash case. Something intriguing about how Ruby operates behind the scenes throws a spanner into the works again. That is, a variable assignment, even if not run, immediately summons that variable into being. For example:
x = 10 if 2 == 5
puts x
Even though the first line won't be run, x will exist on the second line and no exception will be raised. Another nasty one:
x = x
puts x
Whoa! Well, a ||= 42 is working in a similar way. Ruby sees the assignment at the parsing stage and creates the variable in a way that it wouldn't with a || a = 42, even though it ends up behaving like the latter once actual execution occurs.
Further Reading
This appears to have been a popular discussion point in Rubyland over the years, so I would be remiss not to include links to some of the best references:
x ||= y, Redux by Rick DeNatale.
The Reddit discussion about Dave Fayram's post
comp.lang.ruby: Please explain nuances of ||=
comp.lang.ruby: The definitive list of ||= (OR Equal) threads and pages
rubyonrails-talk: What does "||=" mean?
A short-circuit (||=) edge case
And if this tickled your fancy..
Today I've opened up tickets for the 3rd and 4th runs of my Ruby Reloaded online Ruby course. It's aimed at intermediate developers who want to dig deeper, boost their confidence, and bolster their Ruby skill set. We dig into test driven development (TDD), object oriented design, building a library from scratch, code style, and more. It takes place in November and December.
Check out RubyReloaded.com to learn more about the course, what it involves, and when it runs. There are 24 places on each and about half have gone to waiting list folks so far.
P.S. The coupon code INSIDE will give you a $50 discount to thank you for being a Ruby Inside reader!
]]>Tutorialshttps://pinboard.in/u:moonhouse/b:bcf0f0352e5e/Film Grenade2011-10-17T12:48:00+00:00
http://bldgblog.blogspot.com/2011/10/film-grenade.html
moonhousehttps://pinboard.in/u:moonhouse/b:c13c0244d14e/Join the Pen15 club with a vibrator shield2011-10-16T16:40:07+00:00
http://hackaday.com/2011/10/16/join-the-pen15-club-with-a-vibrator-shield/
moonhousehttps://pinboard.in/u:moonhouse/b:c5b274d63e23/Karin MannerstÃ¥l: "Alla har koll pÃ¥ vem jag är" - Ãntligen hemma2011-10-16T11:04:39+00:00
http://www.hemmakanalen.se/1.908618/2011/10/10/karin_mannerstal_alla_har_koll_pa_vem_jag_ar
moonhousehttps://pinboard.in/u:moonhouse/b:c19451bd1373/a bunch of plug-and-play CSS animations2011-10-15T22:25:26+00:00
http://daneden.me/animate/#cta
moonhousehttps://pinboard.in/u:moonhouse/b:55c7a5d7dd4b/Spotify comes to Boxee2011-10-15T21:44:55+00:00
http://gigaom.com/video/spotify-comes-to-boxee/
moonhousehttps://pinboard.in/u:moonhouse/b:c852bf332a3d/Sweet octocopter takes the RED Epic to new heights2011-10-15T21:38:27+00:00
http://hackaday.com/2011/10/12/sweet-octocopter-takes-the-red-epic-to-new-heights/
moonhousehttps://pinboard.in/u:moonhouse/b:3677f79b647e/Ultimaker FAQ: but what about the quality of prints?2011-10-15T21:32:54+00:00
http://davedurant.wordpress.com/2011/10/12/ultimaker-faq-but-what-about-the-quality-of-prints/
moonhousehttps://pinboard.in/u:moonhouse/b:15229506769c/Renee2011-10-15T21:21:12+00:00
http://reneerb.com/
moonhousehttps://pinboard.in/u:moonhouse/b:ef710327e8e0/Handlettered logos from defunct department stores2011-10-15T20:49:06+00:00
http://annyas.com/handlettered-logos-department-stores/
moonhousehttps://pinboard.in/u:moonhouse/b:c4c42f6a5226/A Collection of Beautiful, Free Fonts2011-10-15T07:13:21+00:00
http://smf.is/1yESVy
moonhousehttps://pinboard.in/u:moonhouse/b:0bf2194d08ab/Dennis Ritchie: The Shoulders Steve Jobs Stood On2011-10-14T21:53:43+00:00
http://www.wired.com/wiredenterprise/2011/10/thedennisritchieeffect/
moonhousehttps://pinboard.in/u:moonhouse/b:4f06e916694d/Kern Type, the kerning game2011-10-14T09:16:59+00:00
http://smf.is/1yBt0C
moonhousehttps://pinboard.in/u:moonhouse/b:23ca0029d238/the last time I saw Steve Jobs2011-10-14T07:17:42+00:00
http://pluckytree.tumblr.com/post/12223068604/the-last-time-i-saw-steve-jobs
moonhousestevejobs apple biographyhttps://pinboard.in/u:moonhouse/b:d6e8f4637cf1/Going real simple on HTML5 audio2011-10-13T22:00:00+00:00
http://www.peterbe.com/plog/going-real-simple-on-html5-audio
moonhouse element without any weird plugins and they both support the Ogg Vorbis (.ogg) file format. change log here
So, I used use the rather enterprisey plugin called SoundManager2 which attempts to abstract away all hacks into one single API. It uses a mix of browser sniffing, HTML5 and Flash. Although very promising, it is quite cumbersome. It doesn't work flawlessly despite their hard efforts. Unfortunately, using it also means a 30kb (optimized) Javascript file and a 3kb .swf file (if needed). So, instead of worrying about my very few Internet Explorer users I decided to go really dumb and simple on this.
The solution basically looks like this:
 // somewhere.js
 var SOUND_URLS = {
   foo: 'path/to/foo.ogg',
   egg: 'path/to/egg.ogg'
 }; // play-sounds.js /* Call to create and partially download the audo element.
  * You can all this as much as you like. */
 function preload_sound(key) {
  var id = 'sound-' + key;
  if (!document.getElementById(id)) {
    if (!SOUND_URLS[key]) {
      throw "Sound for '" + key + "' not defined";
    } else if (SOUND_URLS[key].search(/\.ogg/i) == -1) {
      throw "Sound for '" + key + "' must be .ogg URL";
    }
    var a = document.createElement('audio');
    a.setAttribute('id', id);
    a.setAttribute('src', SOUND_URLS[key]);
    document.body.appendChild(a);
  }
  return id;
 } function play_sound(key) {
   document.getElementById(preload_sound(key)).play();
 } // elsewhere.js
 $.lightbox.open({
    onComplete: function() {
       preload_sound('foo');
    }
 });
 $('#lightbox button').click(function() {
    play_sound('foo');
 });
Basically, only Firefox, Chrome and Opera support .ogg but it's a good and open source encoding so I don't mind being a bit of an asshole about it. This little script could be slightly extended with some browser sniffing to work with Safari people but right now it doesn't feel like it's worth the effort.
This make me happy and I feel lean and light. A good feeling!
]]>Web_developmenthttps://pinboard.in/u:moonhouse/b:8c875a848b7d/iOS Fonts2011-10-13T20:03:00+00:00
http://iosfonts.com/
moonhousehttps://pinboard.in/u:moonhouse/b:14c12191ab1b/Talk: Real-time Updates on the Cheap for Fun and Profit2011-10-11T17:42:51+00:00
http://code.flickr.com/blog/2011/10/11/talk-real-time-updates-on-the-cheap-for-fun-and-profit/
moonhouse array( âContent-typeâ => âapplication/atom+xmlâ, âUser-Agentâ => âFlickr Kitten Hoseâ )
Basically a firehose of public uploads/updates (incl. deletions/privacy changes) that we can aim somewhere and turn it on. Similar to the Twitter firehose, but for photos uploaded to Flickr. So essentially stuff happens on Flickr, we transform the events into some easily parseable format, bundle everything up into reasonable-sized blobs and POST it to a web server somewhere that consumes the data.
PubSubHubbub: Thanks, Google
Rather than invent a specific format/protocol we decided to pick something familiar. Something that already has a spec, is well-documented and is well-understood. So we picked a common Publish-Subscribe protocol. Googleâs PubSubHubbub has definitions for how to publish a feed to a hub, how to subscribe and unsubscribe to topics and verify subscriptions and all the other good things that people who write specs like to specify. Of course we didnât actually need a lot of the spec to accomplish our goals for just the firehose bit, but we did have in the back of our minds the thought of expanding on what we built.
So choosing at the start to meet an accepted spec was probably a good idea, and allowed us to get going without having to think too hard about what might come later â because someone else already figured out how that stuff should work.
What?
A hub with no subscription control and a single hard- coded endpoint. If you want to fit the firehose idea into the PubSub metaphor then essentially what we built at first was a hub (i.e all of Flickr) that has one hard-coded âtopicâ that can be subscribed to â namely all public uploads & updates. Except that the subscribing and unsubscribing part involves humans agreeing to things and then turning the firehose on, instead of machines POSTing to web servers and receiving callbacks, etc. But the pubsub metaphor still fits.
How?
So how did we build it? What Iâm going to get into now are what I think are the key pieces of the back-end. Iâll be glossing over some parts of it that are pretty basic and not terribly interesting in the interests of focusing on the good stuff.
Async task system Gearman, etc
The first (and probably the most critical) part of what we built is an asynchronous job queue, or what we often call our Offline Task System. Essentially itâs a way of de-coupling expensive work from the web servers. Sooner or later you end up wanting to perform an operation that takes longer than you want to make a user at the other end wait (or places more load on your web servers than you care to suffer) and so you want to off-load that work somewhere else.
We use this concept EVERYWHERE. Examples: Modifying/deleting large batches of photos. Computing recommendations for who you might want to add as a contact. We have several hundred different tasks, and there are often thousands of them running in parallel. We built our own that fits our specific needs, but a great open-source example is Gearman. Mature, easy to set up and use and scales quite well.
Stuff happens on flickr.
So the very start of the flow of our system begins when stuff happens on Flickr. The obvious example is a photo upload, often involving cats. Other things weâre interested in are updates: Changing the title, the description or other meta-data of a photo. Also we want to provide updates when photos are deleted (or have their visibility switched to private, which in terms of updates should look the same as a deletion)
Insert a task. olt::insert(âpush_new_photoâ, $photo_id);
When any of these things happen, we simply insert a task into our offline task system. Itâs very low cost, doesnât block and once thatâs complete everything else that happens is completely de-coupled for the web servers.
Task runs.
Insert the event into a queue When the task runs, all it does is take the event it represents, transforms it into a little blob of JSON and sticks it in a queue.
Redis Lists
RPUSH kitten_hose blob_of_json
For the queues we chose to use Redis Lists. For those of you not familiar with Redis yet, itâs an open-source, memory-only, key-value store that supports structured data. Think memcached with commonly-used data structures like hashes, sets, and lists and efficient operations on them. At this point Redis is fairly stable and reliable, the performance is fantastic, and itâs dead-simple to use.
We accept a little bit of a HA compromise for the fact that itâs RAM-only and not clustered (yet), so if itâs down youâll drop some updates on the floor. But our goal here is just building a firehose for updates â not a 100%-reliable archive of user activity. We can happily accept the trade-offs that using Redis implies.
Uhhh
Why didnât we just insert into the queue in the first place? At this point it might occur to you that instead of inserting a task (into a queue) that when it runs just inserts something else into another queue, why not just insert the thing into the queue in the first place? Weâll get to that in a bit.
However, two useful properties of our task system are that 1) you can insert tasks with a delay before they run, and 2) task inserts with the same arguments as an existing task fail silently â i.e. you only get the one task.
The upshot is that you can set a delay on things like updates so that a number of updates that happen over a short period (example) only generate a single task â and when it runs it finds all of them.
Then what happens?
Summary:
So at this point youâve got events happening all over Flickr, uploads and updates (around 100/s depending on the time of day), all of them inserting tasks, and the task system grabbing each event and sticking it in a queue, in the form of a Redis list.
The next step is obviously to consume the queue.
Cron
Insert more tasks!
Consume the queue
LPOP kitten_hose
You could have a daemon that sits there and consumes the queue and makes posts to the endpoint and youâre done. Basically what we do is have a cron job that periodically looks at the queue and inserts one or more tasks (depending on the size of the queue) whose job is to drain a particular number of updates from the queue and send them to the endpoint.
At first this is going to seem needlessly complicated but youâll see why when we get to generalize the system for an arbitrary number of subscribers. One thing it does however is provide a convenient way to throttle and buffer the output â depending on what your endpoint can handle you can twiddle the knobs on your task system to run more jobs in parallel, or turn it down to choke off the firehose (and maybe drop updates on the floor if the queue gets too bigâ¦). It gives you flexibility by decoupling the delivery mechanism.
Draw me a picture
Itâs probably time for a simple diagram: Things happening on Flickr trigger the creation of tasks, that run asynchronously, and stuff things into a queue in Redis. Periodically more tasks get triggered to drain the queue and push whatever they find back out to the eventual destination.
It worked pretty well.
Didnât take the site down
Backfill 3B photos
So it turns out that it all actually worked pretty well.
The decoupling of everything using the asynchronous task approach meant that it had pretty much zero impact on the rest of the site. We could develop it live, experiment with capacity etc without having any fear of impacting site performance for our users because of how loosely-coupled all the pieces were â if anything goes wrong the damage is limited to that little piece.
Eventually we decided to run a backfill to a 3rd-party search index of all of our public photos back to the beginning of Flickr (somewhere around 3 billion) and we were able to complete it in 2 weeks, using our existing task system and the only new hardware being one redis box for the queues. So, it worked really well!
Photos from your friends
So we started to ask what if we wanted to make it into something that might be useful on an individual level? It seemed to be pretty reliable and low-impact to the site and showed promise of scaling fairly well. The obvious thing that would be of interest on a user level would be photos from your contacts; Hereâs my endpoint, POST stuff to me when my friends upload new photos (or change existing ones).
Other things that could be of interest are when your contacts favorite a photo, or when you or your contacts are tagged in a photo, or when someone anywhere on Flickr tags a photo with the tag âkittenâ. But letâs start with photos from your contacts.
What?
A list of users (we have those!)
An endpoint (URL)
Looking at what weâd need to add to the system to support user-specific subscriptions thereâs the obvious: a record of the subscription somewhere in a database, the callback mechanism as per the pubhub spec etc. Iâm going to gloss over that because itâs pretty straightforward and not really interesting. What we need to look at to manage the updates and figure out who gets what though is basically a mapping of users (the contacts who upload photos) to endpoints (i.e. subscribers).
Moar Redis
SADD user_1234 endpoint_5678
So we turned to redis again. Redis offers a set datastructure that we can use to maintain this relationship pretty easily. When someone wants to subscribe to photos from their contacts, we create a redis set for each of their contacts and add to it a pointer to the endpoint.
The task again.
SMEMBERS user_1234
foreach $endpoint RPUSH $endpoint json_blob
So now we go back to the Task that gets inserted in response to something happening on Flickr. Where it used to just insert an event into âTheâ single queue, now it looks at the set of endpoints that are interested in uploads from that user and inserts the event into the queue for each of them. Hopefully now you can see why we have a task do this rather than do it on the web server while the user waits â itâs still going to be quick because the queue inserts in redis are constant-time, but if you have a lot of contacts they could add up. Best to just de-couple it all and not worry about running into that problem.
Cron again.
Insert tasks for each queue (endpoint)
Now we turn to draining the queues, and again you can see where the task system comes in. With a large number of endpoints all the cron job has to do is run through each of them, look at how many events need to be consumed and insert an appropriate number of tasks. So scaling the output part of the system (and actually most of the input too) then becomes a matter of scaling your task system â and thatâs a problem thatâs already been solved.
Cache is your friend.
One thing that plays a key role in the system that I havenât talked about is a caching layer. Almost any site of a reasonable size these days has a memcached layer (or something similar) in between the front-ends and the databases. One of the great things this for a push system is that because youâre dealing with things as they happen, all the objects that you typically need to access to build your update stream are almost always in cache â because they were just accessed.
So it turns out that not only does a system like this have almost no impact on your normal page serving time (because of all the de-coupling), it also ends up having very little impact on your databases, due most things being in cache.
Redis Numbers
1000 subscriptions
50K keys (queues) / 300 MB
100 qps â 8-core / 8GB 5% cpu
And a few numbers showing how Redis is performing as our little DIY queueing and subscription system. 1000 subscriptions for various different things takes around 50K keys, consuming 300 MB of ram, and at about 100 qps on an 8-core Linux box itâs barely ticking over.
3 Things: Cache, Tasks, & Queues
So putting all the pieces together itâs actually pretty simple, and relies upon things that you probably already have: a caching layer, some kind of asynchronous task system and rudimentary queueing system. Even if you donât have all of these theyâre pretty well-understood pieces and there are lots of open-source options to choose from: Just grab memcached, gearman, and redis and off you go.
We think you can go a long way to building the back-end of a decent push update system with just these simple pieces. So thatâs the end of my portion of the talk, and now Iâll turn it over to Nolan to talk more about the front-end, and how to make it easier for a client to consume updates.
Why Push? And whatâs in it for me.
So now that Neilâs explained the original reasoning and how we built a system for real-time push, the question is why, as an API consumer, would you want to use it which leads into how to get started with it.
Flickr API = Great Success
Tens of thousands of keys making hundreds of millions of calls per day. By any measure, Flickrâs tradtional pull-based API has been incredibly successful. Developers that have used our API range from Fortune 10 businesses to PhD students to hundreds of thousands of other developers that just want to do something fun with photos and the data around them.
I checked the numbers this wekend and and on average, weâve got around 10,000 different API keys making hundreds of millions of calls per day. Itâs easy. Just use your browser.
One major reason for its popularity is due to how easy it is to use. When you combine data that people want with an API thatâs easy to use, you thousands and thousands of apps built with it.
Thereâs effectively no barrier to entry to get started with using Flickrâs API, if you have a browser, you can access every single API method. And if you want to do this programatically server-side , say a nightly-cronjob that fetches your own uploads, you can can just do a simple âcurlâ. Either way, our pull-based API is a one-liner: whether that line is a URL in your browser, or a one-line shell script.
Weâll curl it for you.
Itâs even simpler than that, if you need it to be. Even if you donât have a server, or donât want to read our documentation, just use the API Explorer on Flickr. Every API method we publicly support is represented here, not just in documentation, but on an actual real-life form for you to build queries with. Just fill out the form, press enter, and weâll curl it for you and spit out the results in pretty JSON or XML format.
One side benefit of this pull-based API is that it also makes debugging easy. You can run tons of API queries as fast as you can debug. This is huge when building a new system. If you formed the call correctly, you get data. If you messed up, modify, rinse, and repeat. Flickr is a visual news feed.
So back to âwhy pushââ¦
Iâm the kind of programmer that needs to have a fairly-focused work environment, but I also like to know whatâs going on in the world at the same time. Twitter is a really great news-before-its-News service, but for me itâs a bit too distracting to have running on a screen next to my code.
Iâve recently hooked up my second monitor to show me two Flickr real-time feeds: the first of which is the Commons, our group of accounts belonging to museums and various historical archives, which is motivational for me, reminding me that Flickr is really something special with real history being stored on it.
The second feed is what I consider my glimpse into whatâs going on around me, the stuff that immediately affects me. So Iâve hooked up a push feed of photos geotagged a half kilometer around my house and a half-kilometer around the office.
Around my house, itâs usually people taking pictures of the Painted Ladies in Alamo Square but then I saw this picture come across. When your entire neighborhood is made up of densely-packed, 50+ year old homes made of questionable building materials, fires are scary things. I then jumped on Twitter and found out there was a multiple-alarm fire just a few blocks from my house. Also, around the office, just this past week, I saw pictures from San Franciscoâs chapter of the OccupyWallStreet protests. The news wasnât on the ground yet but here I was seeing live and extremely relevant things to me. Like they say, a picture can often say more than a thousand words.
Subscribing to a real-time stream of photos from a specific location is about as hyperlocal as you can be. Maybe I wouldnât follow the right people on Twitter, or I wouldnât check the local news site until later that evening, but people do take pictures of important things and events and post them to the site, and it doesnât get much more timely than real-time.
Push is the opposite of Pull. And other obvious facts.
Ok, so back to the technology. Push is a completely different animal than our pull-based APIs. Consuming a real-time push feed flips most things about our API on its head. For starters, youâll need a full-fledged, always-on web server that is exposed to the public Internet. And running on this web server will be a software that is based on a protocol described in a spec-with-a-capital-S. This demands a lot more from the developer than just a one-line curl.
Pull: Hit this URL and read Push: Read this spec and wait
With our regular API, you could basically treat it as a function call, that is âask for something, get somethingâ. With Push, now youâre implementing full protocol where the data will come *eventually*. Now youâll need to wade through pages of dense and sometimes ambiguous instructions, so you can wait for us to tell you that your friend uploa a picture. Another big but obvious difference between the push and pull API is that with Push, your application only gets what we send to you. Thereâs no looking back in time. And due to this read-spec, write-code, and wait and wait some more debug cycle, it takes awhile to get the endpoint working correctly.
Personally, I have access to the Flickr codebase and I still had questions about how to make my endpoint do the right thing and it took me a few good hours one morning and more than one cup of coffee get working right.
So, seriously, why Push?
Because itâs fantastic. Well now that Iâve made Push seem a little scary, seriously, why Push?
The main thing, I think, is that you we give you things as they happen. If you are building a site that uses Flickr data, would you rather us send y data when we get it, or set up a bunch of cronjobs that fetch possibly non-changing data? Even if you like your cronjobs, what happens when yo have 100 users? 1000 users? 1000000? I do want to make one note about what we mean by âreal-time.â As you saw from Neilâs presentation, there are levels of queues and consumers, each having a non-zero delay. We get you the photo data as soon as we can, but this might be a few seconds after we receive up to a minute or two. We understood we were building a real-time feed for photos uploaded to a website, and not sending direction data to a nuclear warhead. It was okay if things were off by a few seconds.
Flickr Globe
Also, receiving real-time photo updates are great for certain types of problems. So, we had the press in the office recently and we wanted to build something cool to run on our big screen behind the developers as we worked. Using the real-time push feed, one of our front-ends, Phil Dokas, was able to build an interactive globe, that charted where on Earth our photos were being uploaded from in real-time.
The great thing about this is, not only was it really pretty looking visualization, but it impressed upon me the magnitude of Flickr being used. The site felt really organic: you could see it being used and growing. For me, it was one of those âpale blue dotâ moments that Carl Sagan talked about, where you get a sense of the bigger picture of what you work on. When you work deep on the backend of Flickr, itâs easy to forget that these are real people from literally everywhere on Earth, uploading things they want to remember.
And using the pushed data made this really easy to build. And for reference, this about 3 minutes worth of publically geotagged photos.
I want to use it, BUT⦠â¦it sounds hard.
So, we think this stuff is awesome, and we want you to use it but we do understand itâs fiddly. The spec is dense and debugging is painful. So weâre going to give you a headstart on the whole thing. Weâve written a tiny web server that handles all the subscription handshake stuff and the parsing of photo data and we put it on GitHub, and open sourced it.
flickr-conduit
https://github.com/mncaudill/flickr-conduit
So weâre introducing, flickr-conduit which is a simple server written in node.js that handles the subscription stuff, keeps tabs on when to unsubsc users, and then finally receives the Flickr posts.
Thereâs a lot of moving parts to setting up a push endpoint: handling everything from getting users authenticating your API key, telling you what topics theyâre interested in, setting up the subscription between your callback and Flickr, and then figuring out how to get those events to the use when Flickr sends them to you.
In the conduit repository, Iâve included a server that implements the push protocol and then just fires off events in JavaScript when Flickr sends something. Iâve also included a PHP application that handles authenticating the user, letting them pick their topics, and then finally showing them the photos they come in as just a demo of what it can do.
I didnât have time to get a slide up for it, but Tom Carden from Bloom, took the PHP application I made and got it ready so that you can easily de it to heroku. Itâs great and if you want to run your own conduit-server demo, Iâd advise checking it out.
To start with, Conduit is the piece that represents your callback endpoint. You tell Flickr that this is your endpoint and it handles the rest of the subscription handshake stuff and when Flickr posts data to you server, it goes to your conduit server.
Pub/Sub all the way down
After I finished building this, I realized that unintentionally I took the idea of pub/sub, that is having a many subscribers expressing interesting in many published streams, and kept that spirit up all the way through to the end of my little node.js server and explaining this model sheds some light on how the conduit server works.
First, as Neil described, Flickr runs a pub/sub service. With conduit, you can run your own pub/sub server that talks to our published streams. And inside of conduit, we let your application code subscribe to certain events that conduit itself receives Flickr post events, and publishes them to your app code to handle how you wish. So there are technically 3 different pub/sub hubs before your app code, which sounds a little complicated, but if you grasp the mental model of how pub/sub works, you understand the full system. Also, keeping the pub/sub levels decoupled from each other provides a lot of simplicity and flexibility.
So, this is a small digression about architecture that I stumbled across while building, that when youâre building systems in the small, it sometimes makes a lot of sense to model the smaller system after the larger system. This may not be groundbreaking for some, but I just found it really neat.
I know âcurlâ. Now, tell me about Push.
With Conduit, weâve removed a fair amount of the fiddly bits so you can get to doing the fun parts later. Iâm going to step you through each of the steps of the whole pubsub flow to show you what each part does.
First, subscribe the user to a topic.
/callback?sub=user1234-contacts-faves
First, youâll want to subscribe the user to a topic. Topics can be anything from their own uploads, to their contacts uploads, to their contacts faves and even photos being geotagged at a specific place.
During this subscription, youâll specify a callback. Once you have conduit running, the callback URL you give Flickr in your subscription should p to the conduit server. One of the tricky parts of handling a multi-user pub/sub server is that you can have many users attached that are waiting for many different strea When Flickr posts a piece of data to your server, you only know the URL that it came in on, so the callback URL needs to be significant so you ro this piece of data to right consumer. One way to handle this is just create a globally unique identifier for a particular subscription, and tuck that in a database and then use that to ma URL to a subscribed user.
Personally, Iâm a fan of reducing the number of moving parts as much as possible so I just use something simple, like the example, and make th URL itself identifiable. So for example if user 1234 wants to subscribe to her contactâs faves, the URL could simply be /user1234-contacts-faves. As long as this callback URL creation algorithm is repeatable, itâs easy to have a common dictionary throughout your app of how to handle a particular subscription.
The part of the play where Flickr asks a question.
Almost immediately, after making the API call to subscribe the user to a topic, Flickr will respond with a âsubscribeâ request. Here Flickr is basically asking, âHi. We just received a subscription request for this callback. Did you send this? If so, repeat the magic password back to me.â All this is described in detail in the spec but you donât need to know any of that. Conduit handles all of this for you.
Debugging: the waiting game.
As I mentioned earlier, debugging the server was the most boring and thus most frustrating part of building an endpoint. Iâd write some code, and to see if did the right thing, I had to wait for on my subscribed events happen and get sent to me. One shortcut I found is that I could subscribe to my own faves, and then I go through a test account and fave photos, therefore forcing events. This sped things up quite a bit.
Someoneâs at the door!
/callback?sub=user1234-contacts-faves maps to user1234-contacts-faves
When an event does occur, Flickr will post it to your callback URL. Conduit then takes this callback URL and through whatever method you decide, creates an event name for it and then passes into a internal structure, In my running example, the callback you see up there gets the event name of âuser1234-contacts-favesâ. Like I said, you could do this mapping of URL to event name however you like, but this is simple and works for me.
The emitter emits.
user1234-contacts-faves
Conduit exposes something that node.js calls an âemitterâ. Itâs basically a pub/sub structure itself. So when a post comes in and you decode the callback URL into an event name, you tell Conduit about it. Effectively youâre saying, âHey I just received some data and it has this event name. Give this data to anyone that is interested in user1234- contacts-faves.â
Finally, fun photo data.
Your application code registers with this emitter what events itâs interested in and when they come in, they do something fun with them. Now Iâm going to explain a bit about the mini-app that I bundled with the conduit server to shows how this works.
Real-time stream
Flickr + conduit + node.js + socket.io. I wanted the final product to be a simple webpage that when my subscriptions were posted to, Iâd see them simply shown up on the page. I glued a few fun tools together and got something really interesting.
PHP is my engine.
Handles the PuSH subscribing and printing out my JS. This entire sample app could easily have been written in JS, but PHP is what I what do all day at work and my JavaScript is a little rusty and I wanted to get something up and running quickly.
I was able to grab former-Flickr engineer, now Etsy CTO, Kellan Elliot-McCraeâs flickr.simple.phpâs library to handle the authentication of the use well as posting of subscription requests.
So the PHP app I built, first authenticates the user with Flickr and then presents the list of real-time topics he or she can subscribe to. The user checks the topics theyâre interested in and then gets redirected to a screen where the images will show up as they come in. I create the unique callback URLs and at the same time dump these event names into the Javascript on the page so that my socket.io code can my node server, what events itâd like to receive when they come in.
Meanwhile, back on the serverâ¦
As mentioned earlier, Flickr will post the photo data to the conduit server to my callback URLs. This callback URL directly becomes the event name, mapping exactly to the what the browser told socket.io that it was interested in. When this event comes in, conduit hands it to the emitter, which then broadcasts the event back out. The server-end of the socket then receives this and pumps down into the browserâs open arms.
And back to the browser.
The browser then receives the photo data and inserts it into the page. That was a whole lot of engineering just to get an image up on the screen and we know it, but with flickr-conduit, you can skip most of the details and just write fun code. This actually turns out to be a great way to explore Flickr.
On my extra monitor at work, Iâve subscribed to my contactsâ faves and all the updates from our Commons area (which includes museums and various archives) to get a weird blend of 100 year old pictures and things my friends find interesting.
So, in summary, this is the why and the how of Flickr added a real-time push feed on the cheap. Since we know the spec is dense, and there are several moving parts, we also hope flickr-conduit helps out new developers that will hopefully le to love our new real-time feeds as much as they love our existing pull feeds.
Thanks.
Related links:
conduit: https://github.com/mncaudill/flickr-conduit
tomâs conduit links: https://github.com/RandomEtc/flickr-conduit-front, https://github.com/RandomEtc/flickr-conduit-back
pubsubhubbub spec: http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.3.html
pua: http://pua.spum.org (http://www.aaronland.info/weblog/2011/05/07/fancy/)
nolanâs conduit: http://nolancaudill.com/projects/conduit/
flickr globe: http://nolancaudill.com/~pdokas/flobe/
kellanâs post: http://laughingmeme.org/2011/07/24/getting-started-with-flickr-real-time-apis-in-php/
neilâs flickr post: http://code.flickr.com/blog/2011/06/30/dont-be-so-pushy/
]]>push pubsub realtimewebhttps://pinboard.in/u:moonhouse/b:0af45e7b9642/Why did iPhone 4S stick with the 3.5-inch screen?2011-10-09T20:51:52+00:00
http://feedproxy.google.com/~r/TheIphoneBlog/~3/vOArY5ARMAI/
moonhousehttps://pinboard.in/u:moonhouse/b:8f718c6f7469/Time lapse of stop-motion puppeteer at work2011-10-05T19:35:17+00:00
http://mgras.soup.io/post/174735008/Time-lapse-of-stop-motion-puppeteer-at
moonhousestopmotion animation timelapse gifanimationhttps://pinboard.in/u:moonhouse/b:9e77e2790c9c/All public government data should be easily machine readable2011-10-03T23:10:03+00:00
http://onlinelabor.blogspot.com/2011/10/all-public-government-data-should-be.html
moonhousehttps://pinboard.in/u:moonhouse/b:9bbdbdcb79f3/Welcome to Google Docs2011-10-03T23:08:52+00:00
https://docs.google.com/document/d/17oqfHHkO48fVFY3sPQqkoCuqFnQOWe4fxRxXJ-lUglg/mobilebasic?pli=1&hl=en_US
moonhousehttps://pinboard.in/u:moonhouse/b:f2cf2c1b2ba3/When "clever" goes wrong: how Etsy overcame poor architectural choices2011-10-03T22:59:33+00:00
http://arstechnica.com/business/news/2011/10/when-clever-goes-wrong-how-etsy-overcame-poor-architectural-choices.ars
moonhousehttps://pinboard.in/u:moonhouse/b:c799743028eb/Skall det verkligen vara så här ?2011-10-02T20:36:38+00:00
http://arskortguldsj.wordpress.com/2011/10/02/skall-det-verkligen-vara-s-hr/
moonhouseLSG_Sky_Chefs Strul Värdecheck X2000https://pinboard.in/u:moonhouse/b:594020ee1b3a/My high school is concerned with safety... wait, what?2011-10-01T22:49:20+00:00
http://imgur.com/kdMPV
moonhousehttps://pinboard.in/u:moonhouse/b:5abd76d8be16/Anonymous Publicly Identifies NYPD Officer Who Cowardly Pepper-Sprayed Protesters | Death and Taxes2011-10-01T22:16:48+00:00
http://www.deathandtaxesmag.com/145523/anonymous-publicly-identifies-nypd-officer-who-cowardly-pepper-sprayed-protesters/
moonhousehttps://pinboard.in/u:moonhouse/b:f1f3b8b57cef/Refusing to Kill Daughter, Pakistani Family Defies Tradition, Draws Anger2011-10-01T22:12:14+00:00
http://www.theatlantic.com/international/archive/2011/09/pakistani-family-refuses-to-kill-daughter-who-was-raped-drawing-anger/245691/
moonhousehttps://pinboard.in/u:moonhouse/b:e5b2948f1a9a/Spamming a label printer with #cookiehammer2011-10-01T21:55:55+00:00
http://hackaday.com/2011/10/01/spamming-a-label-printer-with-cookiehammer/
moonhousehttps://pinboard.in/u:moonhouse/b:e16c2b59454f/distrusting git2011-10-01T21:54:20+00:00
http://benno.id.au/blog/2011/10/01/git-recursive-merge-broken
moonhousehttps://pinboard.in/u:moonhouse/b:c30e8a582b7b/Sinatra 1.3 is out! - The Changelog - Open Source moves fast. Keep up.2011-10-01T21:50:56+00:00
http://thechangelog.com/post/10872694552/sinatra-1-3-is-out-adds-streaming-extensions
moonhousehttps://pinboard.in/u:moonhouse/b:b6d245326231/How To Make An eBook2011-10-01T19:13:43+00:00
http://www.smashingmagazine.com/2011/09/29/how-to-make-an-ebook/
moonhousehttps://pinboard.in/u:moonhouse/b:29d6e76f5366/Get digital plastic surgery thanks to openFrameworks and some addons2011-10-01T14:53:57+00:00
http://hackaday.com/2011/09/30/get-digital-plastic-surgery-thanks-to-openframeworks-and-some-addons/
moonhousehttps://pinboard.in/u:moonhouse/b:6e4dd00a6c64/How to Recreate the Look of Instagram Filters with Vintage Cameras and Films2011-10-01T10:47:57+00:00
http://www.petapixel.com/2011/09/29/how-to-recreate-the-look-of-instagram-filters-with-vintage-cameras-and-films/
moonhousehttps://pinboard.in/u:moonhouse/b:f62fc2d53f16/Instagram Engineering  Sharding & IDs at Instagram2011-10-01T10:40:22+00:00
http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram
moonhousehttps://pinboard.in/u:moonhouse/b:40075eb3f8f5/What's contained in a boarding pass barcode? | shaun ewing | the web site2011-10-01T00:03:34+00:00
http://shaun.net/2011/05/whats-contained-in-a-boarding-pass-barcode/
moonhousehttps://pinboard.in/u:moonhouse/b:47dc3dff7d0f/Passive RFID tag cloning2011-09-30T23:53:57+00:00
http://hackaday.com/2011/09/30/passive-rfid-tag-cloning/
moonhousehttps://pinboard.in/u:moonhouse/b:d35df030396d/coding in the rain · Modern Ruby Development2011-09-30T15:52:27+00:00
http://ascarter.net/2011/09/25/modern-ruby-development.html
moonhousehttps://pinboard.in/u:moonhouse/b:ef39995e366d/SD ljög om skandalfest - à kesson fastnade på bild2011-09-30T12:56:50+00:00
http://smf.is/1xVvc4
moonhousehttps://pinboard.in/u:moonhouse/b:c7dd949b3ecb/Create An Animated Bar Graph With HTML, CSS And jQuery2011-09-27T19:41:47+00:00
http://coding.smashingmagazine.com/2011/09/23/create-an-animated-bar-graph-with-html-css-and-jquery/
moonhouse element could even be adapted to the task. Plenty of charting tools are online that we might use. But what if we wanted something a little more tailored?There are pros and cons to the wide range of resources available to us, but this tutorial will not explore them all. Instead, weâll create our graph using a progressively enhanced sprinkling of CSS3 and jQuery. Because we can.What Are We Making?Weâre making this. And more! Here are some possibilities on how you can extend the techniques explored in this tutorial:A progress bar that indicates how long until the end of all humanity in the event of a zombie plague;â¢Â A graph indicating the decline in safe outdoor activities during a zombie plague;â¢Â A frighteningly similar graph indicating the decline in manners during a zombie plague;â¢Â The increase of people who were unaware of the zombie plague because they were sharing with all of their now-deceased friends on Facebook what they did on FarmVille.Or you could create a graph or quota bar that simply illustrates something useful and less full of dread and zombies. So, letâs â¦
]]>https://pinboard.in/u:moonhouse/b:b5152c29ec4a/Feature: Tutorial: OS X automation with MacRuby and the Scripting Bridge2011-09-27T19:36:36+00:00
http://arstechnica.com/apple/guides/2011/09/tutorial-os-x-automation-with-macruby-and-the-scripting-bridge.ars
moonhousehttps://pinboard.in/u:moonhouse/b:b3feb9741c26/I was once a Facebook fool2011-09-24T19:12:04+00:00
http://public.numair.com/2011_fbfool.html
moonhousehttps://pinboard.in/u:moonhouse/b:915c1f4c6094/Simple Two-Factor SSH Authentication2011-09-24T19:08:40+00:00
https://moocode.com/posts/5-simple-two-factor-ssh-authentication
moonhousehttps://pinboard.in/u:moonhouse/b:a11c69b9a0b0/Be Prepared for Ruby 1.9.3 and 1.9.4: Whatâs New and Whatâs Different2011-09-23T17:28:37+00:00
http://feedproxy.google.com/~r/RubyInside/~3/xx4SPh14-U8/ruby-1-9-3-introduction-and-changes-5428.html
moonhouse "+01:00 +01:00:00"
Time#strftime now supports some extended formats for timezones. :z includes the minutes and ::z gives the full HH:MM::SS.
String#prepend and String#byteslice
Among some changes to the String class are a couple of new methods. First, prepend:
a = 'world'; a.prepend('hello '); a # => "hello world"
String#prepend prepends one string to another, in-place. The result is equivalent to using a[0,0], in this case.
Next, byteslice will let you get access to sections of a string at the byte (rather than character) level:
a = 'hello'; a.byteslice(2, 2) # => "ll"
New character encodings
CP950, CP951, UTF-16, and UTF-32 encodings have been added. Previously, UTF-16 and UTF-32 were available in big-endian (BE) and little-endian specific forms. For example: Encoding.find("UTF-16LE"). I have not yet confirmed if the new UTF-16 and UTF-32 encodings support the byte ordering marks that they should, but am currently assuming so. CP950 and CP951 are Microsoft encodings for Chinese character sets.
Changes to 'Random'
The Random class now accepts ranges on its rand class method. In 1.9.2, this was only allowed on its instance method. For example:
Random.rand(5..9) # => [a number between 5 and 9]
A side effect of this is that Kernel.rand now also supports ranges in 1.9.3. For example:
rand(5..9) # => [a number between 5 and 9]
#__id__ moved from Object to BasicObject
BasicObject is the new grand-daddy of the inheritance tree in Ruby 1.9 and in 1.9.3 it gains access to the functionality of the object_id method by way of __id__ which has been moved into BasicObject from Object. This may help those of you using BasicObject for delegators, proxies, and the like.
BasicObject.new.__id__ # => 2152881920
More?
If you want to pick up on more changes, see the Ruby 1.9.3 NEWS document or, perhaps, check out my Ruby 1.9 Walkthrough screencast ($16) which has an entire section dedicated to things that are new in Ruby 1.9.3.
The Future: Ruby 1.9.4
In her talk, Yugui mentioned two extra production releases of Ruby to come after Ruby 1.9.3. The first was unnamed and was said to be a 1.9 release with minor language changes to 1.9.2/3. In the Q&A, someone asked Yugui if this would be called Ruby 1.9.4 but she said it was still under discussion but hoped it would be called 1.9.4. This unnamed next release would, however, have complete backwards compatibility for code written in Ruby 1.9.2/3.
The Future: Ruby 2.0!
The second release after 1.9.3 "should be called Ruby 2.0", however. It will have significant changes but Yugui notes that "it should be comfortable with 1.9.3" and that you should be able to "safely switch" to 2.0, indicating that any significant changes wouldn't involve removing core language elements or permanently changing core syntax features.
It has previously been said, however, that Ruby 2.0 could be "several years" away, so don't get too excited about this yet. Now is the time to start weighing if you want to influence Ruby 2.0's design, however!
Still getting to grips with Ruby 1.9? Try my walkthrough
I recently released a screencast called Ruby 1.9 Walkthrough, a mega walkthrough of what's new in Ruby 1.9.2 (and Ruby 1.9.3) from the perspective of Ruby 1.8.7. If you're still primarily a Ruby 1.8 based developer and aren't entirely sure about what's new in Ruby 1.9, check it out.
]]>Newshttps://pinboard.in/u:moonhouse/b:06fe7865bef2/Build cheap panning camera mounts for time lapse photography2011-09-21T18:44:15+00:00
http://hackaday.com/2011/09/21/build-cheap-panning-camera-mounts-for-time-lapse-photography/
moonhousehttps://pinboard.in/u:moonhouse/b:9ec7498f82a0/Yahoo blocked e-mails about Wall Street protests2011-09-21T18:34:51+00:00
http://news.cnet.com/8301-1023_3-20109134-93/yahoo-blocked-e-mails-about-wall-street-protests/
moonhousehttps://pinboard.in/u:moonhouse/b:79adfe15f542/