-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
450 lines (248 loc) · 22.5 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
<meta charset="utf-8">
<title>csfam</title>
<meta name="author" content="csfam">
<meta name="description" content="We’ve been distracted and haven’t posted here in a while, but I wanted to share something I had to wrestle with: cross-domain ajax …">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="canonical" href="http://csfam.github.com">
<link href="/favicon.png" rel="icon">
<link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<script src="/javascripts/modernizr-2.0.js"></script>
<script src="/javascripts/ender.js"></script>
<script src="/javascripts/octopress.js" type="text/javascript"></script>
<link href="/atom.xml" rel="alternate" title="csfam" type="application/atom+xml">
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href='http://fonts.googleapis.com/css?family=Ubuntu:400,700|Maven+Pro:700' rel='stylesheet' type='text/css'>
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href='http://fonts.googleapis.com/css?family=Muli:300,400,300italic,400italic' rel='stylesheet' type='text/css'>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js"></script>
<script type="text/javascript" src="http://www.linkedin.com/js/public-profile/widget-os.js"></script>
<link type="text/css" rel="stylesheet" href="/javascripts/galleria/themes/classic/galleria.classic.css">
<script type="text/javascript" src="/javascripts/galleria/galleria.min.js"></script>
<script type="text/javascript" src="/javascripts/galleria/galleria.picasa.min.js"></script>
<script type="text/javascript" src="/javascripts/galleria/themes/classic/galleria.classic.min.js"></script>
<script type="text/javascript">
jQuery.noConflict();
// Use jQuery via jQuery(...)
//jQuery(document).ready(function(){
//jQuery("div").hide();
//});
// Use X with $(...), etc.
//$('html').hide();
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-11362497-4']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body >
<header role="banner"><hgroup>
<h1><a href="/">csfam</a></h1>
<h2>no boring shit</h2>
</hgroup>
</header>
<nav role="navigation"><ul class="subscription" data-subscription="rss">
<li><a href="/atom.xml" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
</ul>
<form action="http://google.com/search" method="get">
<fieldset role="search">
<input type="hidden" name="q" value="site:csfam.github.com" />
<input class="search" type="text" name="q" results="0" placeholder="Search"/>
</fieldset>
</form>
<ul class="main-navigation">
<li><a href="/">Home</a></li>
<li><a href="/about/">About Us</a></li>
</ul>
</nav>
<div id="main">
<div id="content">
<div class="blog-index">
<article>
<header>
<h1 class="entry-title"><a href="/blog/2012/04/08/cross-document-messaging-saves-the-day/">Cross-document Messaging Saves the Day</a></h1>
<p class="meta">
<time datetime="2012-04-08T07:51:00-04:00" pubdate data-updated="true">Apr 8<span>th</span>, 2012</time>
</p>
</header>
<div class="entry-content"><p>We’ve been distracted and haven’t posted here in a while, but I wanted to share something I had to wrestle with: cross-domain ajax uploads. So what’s the problem?</p>
<p>Well, we’ve divided the system into two separate parts: a frontend and a RESTful API (maybe a subject for a future post but in the meantime <a href="https://plus.google.com/112678702228711889851/posts/eVeouesvaVX">check this out</a>). These two parts sit on different domains. This caused me endless headaches when trying to get an image upload mechanism working.</p>
<p><img class="center" src="/images/posts/arch.png" title="udunit general architecture" ></p>
<p>The first problem I had was getting an ajax file upload to work. The gist is that file uploads via XMLHttpRequests aren’t allowed (for security reasons). One workaround involves using an iframe as the upload target, so the response from the POST request is loaded asynchronously into the iframe, giving the impression of an ajax-y upload. (See <a href="http://www.alfajango.com/blog/ajax-file-uploads-with-the-iframe-method/">this post</a> for a much more in-depth discussion of this method.) That wasn’t terribly painful actually.</p>
<p>But at this point there are two domains involved: the frontend domain of the main page where we uploaded from and the API domain of the iframe that we uploaded to. I needed to access the response data within the iframe in order to determine whether the upload was successful and to obtain the uploaded image’s URL. However trying to access the data within the iframe resulted in a browser security exception (cross-domain). The problem is that browsers will not trust XMLHttpRequests’ response data coming from a domain different than the page from which the request is made (hence cross-domain). Trying to access the data throws an error and returns no data.</p>
<p>How do we fix this? It took several days of banging my head against the wall and a great little website called <a href="http://caniuse.com">caniuse.com</a>, where you can discover all the cool features that web browsers implement, are implementing and should be implementing. Enter cross-document messaging.</p>
<p>Cross-document messaging (documented quite well on the <a href="https://developer.mozilla.org/en/DOM/window.postMessage">Mozilla Developer Network</a>) allows you to post a message from one DOM window to another DOM window. The message that is sent can be any arbitrary data. Thus we can send the response data from the iframe (which has its own DOM window) to the parent or container window. The only question I ran into was how to trigger the iframe to fire off the <code>window.postMessage</code> function after the response from the upload was returned. The solution I came up with was to actually return an HTML page as the upload response; the page contains a section of javascript that executes as soon as the page is loaded (in the invisible iframe). The javascript calls the <code>window.postMessage</code> function with the target window being the parent window and the data being the metadata from the upload response. Definitely a hack but it gets the job done – the returned HTML looks something like this:</p>
<pre><code><html>
<body>
<script type='text/javascript'>
window.parent.postMessage({ 'data': 'response data' },'targetWindow');
</script>
</body>
</html>
</code></pre>
<p>where the <code>{ 'data': 'response data' }</code> represents the actual data we wanted to return in the response and <code>targetWindow</code> is the parent window. Then you just need to register an event listener for the “message” event on the parent window (since <code>window.postMessage</code> triggers this event), and the data will be passed to the event handler, therefore allowing you to pass the upload response data from the iframe to the parent window. This allows the upload to be performed asynchronously (ajax-y) and to the upload service sitting on another domain. And ta-da, thanks to cross-document messaging we have image upload working just as we wanted it.</p>
</div>
</article>
<article>
<header>
<h1 class="entry-title"><a href="/blog/2012/01/25/the-tech-behind-udunit/">The Tech Behind Udunit</a></h1>
<p class="meta">
<time datetime="2012-01-25T18:10:00-05:00" pubdate data-updated="true">Jan 25<span>th</span>, 2012</time>
</p>
</header>
<div class="entry-content"><p>One of the first problems we encountered in building Udunit was choosing the technologies we wanted to use. Given three people with relatively strong opinions, agreeing on technologies to use was no easy task. Luckily, after discussing at length our various options, we were able to persuade one another to a more or less unanimous conclusion.</p>
<h3>Hosting</h3>
<p>We were all leaning towards <a href="http://www.heroku.com">Heroku</a> but spent some time discussing the benefits of <a href="http://aws.amazon.com/ec2">Amazon EC2</a>. We liked the idea of having the freedom and control over our servers, but ultimately wanted something that was easy to deploy to and required little maintenance. Heroku gave us the most value for the least amount of work so that was that.</p>
<h3>Database</h3>
<p>After watching one of <a href="http://www.10gen.com/presentations/mongonyc-2011/foursquare">Foursquare’s tech talks</a>, we became enamored with <a href="http://www.mongodb.org">Mongodb</a> and wanted to use it in Udunit. The parts that particularly appealed to us were the JSON style storage, auto-scaling/sharding and full index support. We were a little wary about using NoSQL, considering all of us were more used to relational databases like MySQL, but we were excited about the possibilities. Plus, despite our familiarity with MySQL, we were also frustrated with the hassle in scaling, the restriction in schema design and the performance.</p>
<h3>API Framework</h3>
<p>A few of us also pushed for using <a href="http://liftweb.net/">Lift/Scala</a> for our API framework (hint: Foursquare <a href="https://docs.google.com/present/view?id=dcbpz3ck_25czcns2c2&revision=_latest&start=0&theme=blank&cwj=true">uses</a> it). Honestly, the biggest selling point here for us was the novelty of using a new language that reduces the verbosity of Java and encourages functional programming.</p>
<h3>Web Framework</h3>
<p>We had a variety of options here. A couple of us have used Django, GWT and Struts before so we had some stronger opinions (one of which was absolutely no GWT). However, considering we were using Lift for our API framework, we ultimately decided that Lift on the frontend would accelerate our learning curve and also simplify the number of technologies we had to learn. We were also intrigued by the idea behind Snippets which seemed like a completely new way of thinking about frontend design.</p>
<h3>Conclusions thus far..</h3>
<p>We’ve been using these technologies for a couple weeks now. Scala has proven to be an extraodinary language with a bit of a painful learning curve. But, so far, no complaints. We’re excited to be learning these technologies and having fun while doing it!</p>
</div>
</article>
<article>
<header>
<h1 class="entry-title"><a href="/blog/2012/01/17/measuring-herokus-concurrent-request-performance/">Measuring Heroku’s Concurrent Request Performance for Long-running Requests</a></h1>
<p class="meta">
<time datetime="2012-01-17T00:32:00-05:00" pubdate data-updated="true">Jan 17<span>th</span>, 2012</time>
</p>
</header>
<div class="entry-content"><p>I’ve been meaning to write some posts here for a while, and I’m glad I’m finally getting around to it. The first thing I wanted to write about is some testing we did a couple months back with the number of concurrent user requests that could be handled by <a href="http://www.heroku.com">Heroku</a> using a variety of backend technologies. But first off, in case you’ve managed to miss it – what is Heroku, why are we using it, and how does it work?</p>
<ul>
<li>It is a cloud-based application platform with built-in scalability and management tools.</li>
<li>It makes things dead simple from deployment to scaling up.</li>
<li>It’s free as long as you stay under a monthly traffic limit, which is perfect if you’re just starting up your idea.</li>
<li>Essentially dynos handle web requests within the Heroku architecture, and scaling up your application is just a matter of increasing the number of dynos you are using. Piece of cake.</li>
</ul>
<p>One of the other nice things about Heroku is it provides developers with a good amount of freedom in terms of what languages and frameworks can be used. Heroku will support JVM-based languages (Java, Scala, etc.), Ruby, Node.js, and Python. We were considering a number of options for the language and framework to use for our latest project, <a href="http://demo.udunit.com">udunit</a>, and we had narrowed our list down to <a href="http://scala-lang.org">Scala</a> and the <a href="http://liftweb.net/">Lift framework</a>, <a href="http://www.python.org">Python</a> and the <a href="https://www.djangoproject.com/">Django framework</a>, or <a href="http://nodejs.org">Node.js</a> and the <a href="http://expressjs.com">Express framework</a>.</p>
<h2>The Tests</h2>
<p>We set up very simple Heroku projects – one for each of the three frameworks mentioned above – that would result in a long-running request (i.e. the server was “busy” generating the response for ~2 seconds). Using the <a href="http://httpd.apache.org/docs/2.4/programs/ab.html">Apache Bench</a> tool, we were able to do some load testing of the various frameworks running on Heroku. What we really wanted to test was how well a single Heroku dyno would handle concurrent requests. So we ran tests via Apache Bench with increasingly more concurrent requests: 1, 2, 3, 4,5, 10, 20. The tests each hit a page which would trigger a long-running request. The tests were executed with a command like</p>
<pre><code> ab -n 200 -c 20
</code></pre>
<p>for 200 total requests with 20 requests at a time. Apache Bench provides data on the requests sent, such as the average number of requests handled per second (see graph below) or the min/max time taken to handle a single request. Using this data we were able to get an idea of what one Heroku dyno could handle.</p>
<h2>The Results</h2>
<p>Here we have a chart showing the number of requests handled per second for each of the three frameworks. Everyone was able to keep up while the number of concurrent requests was small; at 5 concurrent requests, all the frameworks were handling ~2.5 requests per second – so pretty close to ideal (5 requests / 2 second long-running request = 2.5 requests per second).</p>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js"> {"dataSourceUrl":"//docs.google.com/spreadsheet/tq?key=0AlrawxK1noHLdExqRUhLWFp6YXkwaFVyOENseE1TZkE&transpose=0&headers=1&merge=COLS&range=B2%3AB9%2CH2%3AH9%2CH14%3AH21%2CH26%3AH33%2CI2%3AI9&gid=0&pub=1","options":{"vAxes":[{"title":"requests per second handled","minValue":null,"viewWindowMode":"pretty","viewWindow":{"min":null,"max":null},"maxValue":null},{"viewWindowMode":"pretty","viewWindow":{}}],"series":{"1":{"color":"#109618"},"3":{"color":"#dc3912"}},"booleanRole":"certainty","title":"Concurrent requests handled via Heroku","animation":{"duration":500},"vAxis":{"format":""},"useFirstColumnAsDomain":true,"hAxis":{"title":"concurrent requests","format":""},"isStacked":false,"width":600,"height":371},"state":{},"view":{"columns":[{"calc":"stringify","type":"string","sourceColumn":0},1,2,3,4]},"chartType":"ColumnChart","chartName":"Chart 1"} </script>
<p>When the load started getting higher, performance began dropping off (mainly in the python-django setup, somewhat in the scala-lift setup, hardly at all for node.js and express). Moving up to 50 concurrent requests, both Django and Lift became hardly useable, though surprisingly Express maintained a very high level of performance. Node.js and Express were the clear winners here, though it should be noted that we were going with the default configuration for Lift and Django. With better tuning of the server configuration, we could probably get higher performance from these two frameworks.</p>
<p>In the end we decided to go with the Lift framework. It’s performance was still strong and increasing system responsiveness while under high load is just a matter of increasing the number of Heroku dynos being used. Lift also provides a much fuller and more powerful framework than Express does. In the end Lift’s strong performance and rich set of features won us over. But I’m definitely going to push for some Node.js projects in the future ;)</p>
</div>
</article>
<article>
<header>
<h1 class="entry-title"><a href="/blog/2012/01/05/in-the-beginning/">In the Beginning</a></h1>
<p class="meta">
<time datetime="2012-01-05T23:53:00-05:00" pubdate data-updated="true">Jan 5<span>th</span>, 2012</time>
</p>
</header>
<div class="entry-content"><p>There was this group of people, who got to know each other in the basement of a computer lab. They were a talented bunch, during their time in the lab they built interesting projects and had fun working with each other. They made a good team. Then the good times were over and they had to graduate. They all went their separate ways, but many of them later, during cold rainy nights sitting in front of computers in cubicles working on other people’s work, would remember those good times and wish they could be part of something like that sometime again.</p>
<p>Many years later, they get laid-off from their jobs at the big corporations to be replaced by new dream-filled youth – youth just as ready to give up their dreams, creativity and energy in exchange for job security. As they leave the building and watch the new hires take their places they wonder if it could have been different.</p>
<p>…</p>
<p>Wait a sec! It can be different! We are all talented, energetic, and good at what we do! We are creative. We love applying ourselves to new projects. There is no reason not to harness this power! We are powerful! We love cs and graphics and making things. We are scientists and inventors, artists and artisans, and we are funny and fun. We play flash games and we waste time on tv shows, and we create and deliver.</p>
<p>CSFAM – is the chance for all of us to do what we want, what we’re interested in, to create the work that we love with the people we love working with.</p>
</div>
</article>
<div class="pagination">
<a href="/blog/archives">Blog Archives</a>
</div>
</div>
<aside class="sidebar">
<section>
<h1>Recent Posts</h1>
<ul id="recent_posts">
<li class="post">
<a href="/blog/2012/04/08/cross-document-messaging-saves-the-day/">Cross-document messaging saves the day</a>
</li>
<li class="post">
<a href="/blog/2012/01/25/the-tech-behind-udunit/">The Tech Behind Udunit</a>
</li>
<li class="post">
<a href="/blog/2012/01/17/measuring-herokus-concurrent-request-performance/">Measuring Heroku’s concurrent request performance for long-running requests</a>
</li>
<li class="post">
<a href="/blog/2012/01/05/in-the-beginning/">in the beginning</a>
</li>
</ul>
</section>
<section>
<h1>Github Repos</h1>
<ul id="gh_repos">
<li class="loading">Status updating…</li>
</ul>
<a href="https://github.com/csfam">@csfam</a> on Github
<script type="text/javascript">
$.domReady(function(){
if (!window.jXHR){
var jxhr = document.createElement('script');
jxhr.type = 'text/javascript';
jxhr.src = '/javascripts/libs/jXHR.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(jxhr, s);
}
github.showRepos({
user: 'csfam',
count: 0,
skip_forks: true,
target: '#gh_repos'
});
});
</script>
<script src="/javascripts/github.js" type="text/javascript"> </script>
</section>
<section class="tag-cloud">
<h1>Tags</h1>
<a style='font-size: 0.80em' href='/blog/tags/fileupload'>fileupload</a>
<a style='font-size: 0.80em' href='/blog/tags/framework'>framework</a>
<a style='font-size: 1.80em' href='/blog/tags/lift'>lift</a>
<a style='font-size: 0.80em' href='/blog/tags/cross-domain'>cross-domain</a>
<a style='font-size: 0.80em' href='/blog/tags/ramblings'>ramblings</a>
<a style='font-size: 1.80em' href='/blog/tags/scala'>scala</a>
<a style='font-size: 0.80em' href='/blog/tags/mongodb'>mongodb</a>
<a style='font-size: 0.80em' href='/blog/tags/django'>django</a>
<a style='font-size: 0.80em' href='/blog/tags/cross-document'>cross-document</a>
<a style='font-size: 0.80em' href='/blog/tags/api'>api</a>
<a style='font-size: 0.80em' href='/blog/tags/ajax'>ajax</a>
<a style='font-size: 0.80em' href='/blog/tags/database'>database</a>
<a style='font-size: 1.80em' href='/blog/tags/heroku'>heroku</a>
<a style='font-size: 0.80em' href='/blog/tags/python'>python</a>
<a style='font-size: 0.80em' href='/blog/tags/nodejs'>nodejs</a>
<a style='font-size: 0.80em' href='/blog/tags/xdr'>xdr</a>
<a style='font-size: 0.80em' href='/blog/tags/hosting'>hosting</a>
<a style='font-size: 0.80em' href='/blog/tags/technology'>technology</a>
<a style='font-size: 0.80em' href='/blog/tags/performance'>performance</a>
</section>
</aside>
</div>
</div>
<footer role="contentinfo"><p>
Copyright © 2012 - csfam -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script type="text/javascript">
var disqus_shortname = 'timtregubov';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
</body>
</html>