Alexis Smirnov http://weblog.smirnov.ca Most recent posts at Alexis Smirnov posterous.com Sun, 06 Feb 2011 06:41:03 -0800 Enough snow? http://weblog.smirnov.ca/enough-snow http://weblog.smirnov.ca/enough-snow

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Thu, 11 Nov 2010 09:12:00 -0800 Looking for a simpler way to work with the SproutCore store and records http://weblog.smirnov.ca/looking-for-a-simpler-way-to-work-with-the-sp http://weblog.smirnov.ca/looking-for-a-simpler-way-to-work-with-the-sp
This post is about SproutCore programming and assumes familiarity with the framework.

The traditional pattern of working with store's records is to set up a binding via a controller and handle a data change event. At high level, it goes something like this:

1. Request the creation of RecordArray via App.store.find(<some query>) method
2. Set the record array as the "content" in an ArrayController
3. Bind a view to the content property of that ArrayController

First two steps are done together, usually when a state is setup. For example, say you want to show some contacts. You'd write some something like this:

App.contactsState = SC.Responder.create( {
didBecomeFirstResponder : function() {
var records = App.store.find(App.contactsQuery);
App.contactsController.set('content', records);
}
});

The third step of binding is done in a view eg.

view = App.ContactsView.design({
contentBinding : 'App.contactsController.arrangedObjects'
});

This pattern works great when you need a static relationship between a piece of data and a view. In this example we have a static binding between a set of contacts and the view that shows them.

However there are cases that don't call for a static binding relationship. Cases where an app simply wants to make a query, get the data, and act on it. These cases usually happen then an app needs to process a event eg. user action (button click), or server response. Handling these cases is quite convoluted with the pattern above. 

For example, say you need to implement a button that sends a message to a subset of your contacts eg. "favorite contacts". 

You cannot write:

onClickSendMessageToFavoriteContacts: function() {
var favoriteContacts = App.store.find(App.favoriteContactsQuery);
favoriteContacts.forEach(function(contact) {App.sendSomeMessage(contact);});
}

because find() cannot return the results when they haven't been retrieved yet (from the server, from local DB, etc.). By the time find() returns the RecordArray favoriteContacts can be empty and would be in the BUSY_LOADING state.

Instead the button handler would have to do the following:

1. create a new query -- because we want to select a subset of the data given a specific criteria (eg. select favorite contacts)
2. create a new controller -- because we need a way to be notified when the results of the query are available
3. setup an observer/binding that will wait until the results are available 
4. perform the action (sending a message to favorite contacts)
5. tear down the observer relationship -- because we no longer interested in paying the cost of having "favorite contacts" be kept up to date
6. remove the record array -- because the array is no longer needed and would simply take up memory

Ideally we'd want a more direct way to act on the results of queries. Imagine being able to write:

App.Contact.objects().filter({varotite: YES}, function(contacts) {sendMessage(contacts);});

A filter() method would perform all the necessary steps to make sure that when the callback is called, the data is available. It would also tear-down all the bindings needed to make it happen. Similarly, one can imagine an API like:

App.Contact.objects().all().del()
or
App.Contact.objects().all(function(records) {dome something with all Contacts})

Those who are familiar with Django will recognize this API as similar to QuerySet (http://docs.djangoproject.com/en/dev/ref/models/querysets/), but modified to deal with asynchronous nature of JavaScript programming.

Getting an object would become:
App.Contact.objects().runGet({guid: '123'}, function(contact) { do something with contact 123 });

A multi-step operation such as getting or creating an object can also be hidden inside a method (see Django's version here: http://www.djangoproject.com/documentation/models/get_or_create/):

App.Contact.objects().runGetOrCreate({firstName: 'John', lastName: 'Lennon'}, {'birthday': '1940-10-9'}, function(john) { ... });

I've put an implementation sketch here:
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

App.ObjectsController = SC.ArrayController.extend({
/**
* Pseudo-synchronous API to handle all objects of a given type.
*
* This API in intended to hide the asynchronous nature of retrieving
* records by providing a callback to be called when the data in available.
*
* Example usage:
* App.MyModel.objects().all(function(obj) {console.log(obj);));
*/
all: function(onSuccess, onError) {
var records = this.get('content'),
_statusDidChange = function() {
if( this.status & SC.Record.READY_CLEAN && onSuccess) {
// Now that the records are in READ_CLEAN state, call
// the callback
onSuccess(this);

// Now that we've handled the event, we no longer need
// to be listening for the status
records.removeObserver('status', statusDidChange);
}
};

// No records yet, launch the find() request for all objects of the
// parentType
if( !records ) {
var parentType = this.get('parent');
var store = this.get('store');

records = store.find(parentType);
this.set('content', records);
}

// If the records aren't ready yet, defer calling onSuccess
if( onSuccess ) {
if( records.status & SC.Record.READY_CLEAN )
onSuccess(records);
else
records.addObserver('status', _statusDidChange);
}
return this;
},

/**
* Delete all objects contained objects
*/
del: function() {
var records = this.get('content'),
_del = function(records) {
records.forEach(function(record) {
record.store.destroyRecord(undefined,
undefined,
record.storeKey);
});
records.destroy();
};

if( records.status & SC.Record.READY_CLEAN ) {
_del(records);
} else {
var _statusDidChange = function() {
if( records.status & SC.Record.READY_CLEAN ) {
console.log('deleting %@'.fmt(this));
_del(this);
this.removeObserver('status', statusDidChange);
}
};
records.addObserver('status', _statusDidChange);
}
},

runGet: function(queryConditions, onSuccess, onError) {
var parentType = this.get('parent'),
store = this.get('store'),
queryString = '',
andString = '',
query = null,
records = null,
_statusDidChange = function() {
console.log('status change: %@'.fmt(records.status));

if( records.status & SC.Record.READY_CLEAN ) {
if( records.length() === 1 && onSuccess ) {
onSuccess(records.objectAt(0));
}
if( records.length() != 1 && onError ){
onError();
}

// Now that the READY state is handled, the observer is
// no longer needed. So remove it.
records.removeObserver('status', _statusDidChange);
records.destroy();
}
};

for( condition in queryConditions ) {
if (queryConditions.hasOwnProperty(condition)) {
queryString = '%@ %@ %@="%@"'.fmt(queryString, andString, condition, queryConditions[condition]);
andString = "and";
}
}

query = SC.Query.local(parentType, queryString);
records = store.find(query);

if( records.status & SC.Record.READY_CLEAN ) {
_statusDidChange();
} else {
records.addObserver('status', _statusDidChange);
}
},
/**
* Usage example:
*
* MyApp.MyModel.objects().getOrCreate(
* 'guid = 1',
* {quid: 1, foo, 'bar'},
* function(result, created) {
* console.log('got %@ created? %@'.fmt(result, created);
* });
*/
getOrCreate: function(queryConditions, defaults, onSuccess, onError) {
var parentType = this.get('parent'),
store = this.get('store'),
queryString = '',
andString = '',
query = null,
records = null,
_createRecord = function() {
// If the conditions or defaults include the primary key,
// it will be extracted from the defaults and be used as the ID
// for the record.
var record = store.createRecord(parentType, defaults);
onSuccess(record, YES);
},
_statusDidChange = function() {
if( records.status & SC.Record.READY_CLEAN ) {
console.log('callback received records ready');
if( records.length() > 1) {
var handler = onError || console.log;
handler('getOrCreate returned %@ records'.fmt(records.length()));
}
if( records.length() === 0) {
_createRecord();
}
if( records.length() === 1 && onSuccess ) {
onSuccess(records.objectAt(0), NO);
}
// Now that the READY state is handled, the observer is
// no longer needed. So remove it.
records.removeObserver('status', _statusDidChange);
records.destroy();
}
};

for( condition in queryConditions ) {
if (queryConditions.hasOwnProperty(condition)) {
queryString = '%@ %@ %@="%@"'.fmt(queryString, andString, condition, queryConditions[condition]);
andString = "and";
defaults['%@'.fmt(condition)] = queryConditions[condition];
}
}
query = SC.Query.local(parentType, queryString);
records = store.find(query);

if( records.status & SC.Record.READY_CLEAN ) {
_statusDidChange();
} else {
records.addObserver('status', _statusDidChange);
}
}
});
/*---------------------------------------------------------------------------*/

App.Record = SC.Record.extend({});
App.Record.mixin({
_objects: null,
objects: function() {
if( !this._objects ) {
this._objects = App.ObjectsController.create({parent: this, store: App.store});
}
return this._objects;
}
});

App.Account = App.Record.extend( {
accountClass : SC.Record.attr(String, {defaultValue: 'email/gmail'}),
password : SC.Record.attr(String),
name : SC.Record.attr(String)
});

App.User = App.Record.extend( {
username : SC.Record.attr(String)
});

App.Message = App.Record.extend({
body : SC.Record.attr(String)
});
and would love to hear any feedback. It is structured as a mixin to the Model and tracks the record states in order to call the callback at the right time.

Do you think SC's data model API should be improved? Can it be improved? Am I approaching the implementation from the right perspective? Does this idea have any fundamental issues with performance?

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Thu, 01 Jul 2010 15:21:00 -0700 Stanford's Entrepreneurship Corner: Marc Andreessen http://weblog.smirnov.ca/stanfords-entrepreneurship-corner-marc-andree-1 http://weblog.smirnov.ca/stanfords-entrepreneurship-corner-marc-andree-1

Great Q&A on entrepreneurship.

Marc Andreessen is soft-selling his new VC fund, but he does it in a way to provide a real value to listeners beyond letting them know about his investment philosophy.

On criteria for selecting a business idea.

It is quite similar to criteria of selecting an investment:
1. Biggest market (new or existing)
2. 10x change in technology (or economic change). The premise is that existing companies "generally do a good job" at what they do, so you need a leverage of a profound change to start a new company
3. Team that includes at least one technologist. Two is better than one.
4. A product that becomes a company is better than a company that decides to build a product.

Q: "Can a mobile app company have enough potential to fundable?"
A: "It depends".
He is avoiding category-based investment decisions or presuming anything about company's potential simply by the fact it belongs to one or the other category. Example he gave is "enterprise software" was considered dead category in the begging of 00s, but resulted in great investments.

On building a team:
Recruiting and talking people out of quitting are the two hardest things to do at a startup. Selling a vision is a key skill for the funding team.

Great point about the value of "polarizing" product. It is OK to have lots of people hate the product as long as there are people who really love it. Describing your company in stark terms helps filter out candidates who aren't the right fit anyway.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Thu, 08 Apr 2010 08:04:44 -0700 StartupSquare Montreal and MTL NewTech http://weblog.smirnov.ca/startupsquare-montreal-and-mtl-newtech http://weblog.smirnov.ca/startupsquare-montreal-and-mtl-newtech

Montreal is a happening place. There’s StartupDrinks. There’s the launch of a new seed fund, Founder Fuel. The announcement of another StartupCamp. There comes two new players: StartupSquare and MontrealNewTech.

StartupSquare

StartupSquare Montreal

StartupSquare is hosting their kick off event on April 13, 2010. The group is made up students at McGill University, Concordia University, HEC Montreal, and other local universities. The goal of the group is to help promote entrepreneurship and commercialization to create growth companies. It is roughly modeled on Aalto Entrepreneurship Society which was started by StartupSquare co-organizer Riku Seppala.

Montreal New Tech

Montreal New Tech

Montreal New Tech is headed by Felipe Coimbra aka TwtFelipe who got some coverage this week by Mark Suster around US immigration policy and the Founder Visa. MTLNewTech is a great example of the evolution of community. It has taken the best part of DemoCamp, Web Innovators Group, TECHCocktail and other events over the past formative years. And it has evolved to help enable, educate and connect local tech entrepreneurs, i.e., it’s Felipe doing the things that help him with 63 Squares and YowTrip!

It is great to see entrepreneurs take responsibility for ensuring that the events and activities they need and want are created. Make sure you check out both of these groups, they are doing great things.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Wed, 07 Apr 2010 07:19:15 -0700 Amazon Simple Notification Service http://weblog.smirnov.ca/amazon-simple-notification-service http://weblog.smirnov.ca/amazon-simple-notification-service Amazon continues to run away with this cloud thing. Its new service is called "Simple Notification Service" and it appears to do what it says:

Pastedgraphic-1

Create Topic "My Topic":
POST http://sns.us-east-1.amazonaws.com/?Action=CreateTopic&Name=My-Topic
Subscribe to "My Topic":
POST http://sns.us-east-1.amazonaws.com/?Action=Subscribe&TopicArn=sns.us-east-1.amazonaws.com/My-Topic&Protocol=https&Endpoint=https://myapp.com/mytopic/
Publish "hello world" to "My Topic":

Delete "My Topic" when you're done:
POST http://sns.us-east-1.amazonaws.com/?Action=DeleteTopic&Name=My-Topic

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Wed, 07 Apr 2010 07:03:01 -0700 A 2.5 Year-Old Uses an iPad for the First Time http://weblog.smirnov.ca/a-25-year-old-uses-an-ipad-for-the-first-time-8 http://weblog.smirnov.ca/a-25-year-old-uses-an-ipad-for-the-first-time-8

Many have some to realize the revolutionary notion of multitouch, but this video really make the point crystal clear. I cannot think of another general-purpose computer user interface that can pass such a test.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Wed, 31 Mar 2010 05:41:37 -0700 Google Code Blog: OAuth access to IMAP/SMTP in Gmail http://weblog.smirnov.ca/google-code-blog-oauth-access-to-imapsmtp-in http://weblog.smirnov.ca/google-code-blog-oauth-access-to-imapsmtp-in

Google has long believed that users should be able to export their data and use it with whichever service they choose. For years, the Gmail service has supported standard API protocols like POP and IMAP at no extra cost to our users. These efforts are consistent with our broader data liberation efforts.

In addition to making it easier for users to export their data, we also enable them to authorize third party (non-Google developed) applications and websites to access their data at Google. One of the more common examples is allowing a social network to access your address book in order to send invitations to your friends.

While it is possible for a user to authorize this access by disclosing their Google Account password to the third party app, it is more secure for the app developer to use the industry standard protocol called OAuth which enables the user to give their consent for specific access without sharing their password. Most Google APIs support this OAuth standard, and starting today it is also available for the IMAP/SMTP feature of Gmail.

The feature is available in Google Code Labs and we have provided a site with documentation and sample code. In addition, Google has begun working with other companies like Yahoo and Mozilla on a formal Internet standard for using OAuth with IMAP/SMTP (learn more at the OAuth for IMAP mailing list).

One of the first companies using this feature is Syphir, in their SmartPush application for the iPhone, as shown in the screenshots below. Unlike other push apps, Sypher's SmartPush application never sees or stores the user’s Gmail password thanks to this new OAuth support.

We look forward to finalizing an Internet standard for using OAuth with IMAP/SMTP, and working with IMAP/SMTP mail clients to add that support.

By Eric Sachs, Senior Product Manager

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Thu, 25 Mar 2010 13:13:37 -0700 Placehold.it http://weblog.smirnov.ca/placeholdit http://weblog.smirnov.ca/placeholdit

I was going to say this is very similar to http://dummyimage.com but with more options, but it looks like they've also added colour and text options too.

trovster - 20th March 2010 16:03 - #

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Thu, 25 Feb 2010 07:10:13 -0800 Wanted: Greasemonkey script to share Hacker News up-votes http://weblog.smirnov.ca/wanted-greasemonkey-script-to-share-hacker-ne http://weblog.smirnov.ca/wanted-greasemonkey-script-to-share-hacker-ne How's this for a mouthful? What I want is actually quite simple, if you know what is Greasemonkey and Hacker News.

Need more detail? Let me explain: I read Hacker News. Sometimes I up-vote the posts. I wouldn't mind sharing those stories on Facebook, Twitter, this blog, but can't bring myself to make another half-dozen clicks to do so. Call me sharing-lazy. Hacker News is a minimalist/low tech news site, so I don't expect his author to introduce such integration anytime soon. But that should not stop a developer from adding it via greasemonkey script.

Perhaps good folks of Posterous would be interested to supplying such a script that automatically shares up-votes via post.ly?

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Sat, 20 Feb 2010 20:17:01 -0800 How to Replace IMAP http://weblog.smirnov.ca/how-to-replace-imap http://weblog.smirnov.ca/how-to-replace-imap
I believe that one of the reasons for the lack of innovation in the email space is the lack of a simple yet powerful email access protocol. Every developer that wants to try something with email needs to first jump through the hoops of IMAP and MIME, or worse, the Outlook Object Model and MAPI. A new protocol like reMAP would lift this burden off their shoulders. We've seen what open, simple standards can do for innovation with Twitter's and Flickr's API. Now imagine unleashing the same sort of creativity to the vast ocean of data that is email.

Web apps that generate and host personal information are providing that information to apps via OAuth. Email - on of the key datatypes of personal information - is still only accessible via non HTTP protocol. It is time for a change.

I suspect that Google re-hiring Gabor (and killing reMail in the process) has a lot to do with this vision.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Thu, 18 Feb 2010 07:08:04 -0800 The Google Account problem http://weblog.smirnov.ca/the-google-account-problem http://weblog.smirnov.ca/the-google-account-problem
Every so often you experience a technical problem you can’t find any information about and which takes you forever to solve. Then, after you finally solve it, you are left scratching your head saying, “I don’t get it­—there must be millions of people with this problem—why is there so little information about it?

This post is a powerful illustration that the design online identity are much harder to get right than it seems. Unfortunately there the industry didn't yet find the design pattern that works. And the problem is growing with the number of people that have multiple email addresses and multiple identities.

Google clearly didn't get it right. Anyone else has?

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Wed, 17 Feb 2010 13:52:55 -0800 do http://weblog.smirnov.ca/do-6688 http://weblog.smirnov.ca/do-6688

do. A library for Node that adds a higher level abstraction for dealing with chained and parallel callbacks.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Tue, 16 Feb 2010 13:57:26 -0800 Disqus Commenting System http://weblog.smirnov.ca/disqus-commenting-system http://weblog.smirnov.ca/disqus-commenting-system My weblog is now running Disqus - a global comment system that improves discussion on websites and connects conversations across the web. Hopefully it will make the commenting easier.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Tue, 16 Feb 2010 06:43:00 -0800 ZSync: sync library http://weblog.smirnov.ca/zsync-sync-library http://weblog.smirnov.ca/zsync-sync-library

ZSync is an open source syncing library designed to allow easy syncing of data between an iPhone/iPod Touch and the OS X Desktop.

ZSync utilizes the BLIP library and Apple’s Sync Services to allow easy and seamless syncing of data. 

The library is based BLIP - a message-oriented network protocol that lets the two peers on either end of a TCP socket send request and response messages to each other. It's a generic protocol, in that the requests and responses can contain any kind of data you like. It's somewhat like Jabber/XMPP, and somewhat like HTTP, and a lot like BEEP.

You can read a more detailed overview of BLIP, or examine the protocol specification.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Mon, 15 Feb 2010 11:06:50 -0800 Google Buzz re-invents Gmail - O'Reilly Radar http://weblog.smirnov.ca/google-buzz-re-invents-gmail-oreilly-radar-1 http://weblog.smirnov.ca/google-buzz-re-invents-gmail-oreilly-radar-1
Tim O'Reilly:
There are real benefits to using email as a social media platform. Just about everyone knows how to use it. (Despite claims that young millenials look down on email, it's just too useful to go away anytime soon.) It's incredibly flexible - you can share anything you want, and comment on it at any length, from 140 characters to as many as it takes to get your point across. It has a global address space that allows you to find almost anyone, an address space that links people to content. It's multi-platform, and accessible from anywhere.

This description of benefits of email is dead-on. And the benefits apply well beyond social media. But there's another key property of Email that makes it so ubiquitous: Email is multi-client and is multi-server.

When you email someone or get an email from someone, you don't care about what client, or server your counterpart is using. A system that makes the user pay attention to this stuff will not be as universal as email.

Twitter and Facebook are guilty to have created their own address space that parallels email. So Buzz is closer to be running on "email" than traditional social networks. In that respect it deserves Tim's kudos.

But in one key respect Buzz is still foreign to Email system. You have to be "on Google Gmail" to benefit from this new capability. Ask this question: when you send a photo in an attachment to you fiend's email address, do you think about what email provider she is on? Or what version of email client she is using?

Could people who don't have Google Account send Buzz "messages" to each other? My understanding they cannot. This is the key difference with email thus I'm skeptical Buzz will become as ubiquitous as email.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Sat, 13 Feb 2010 12:27:50 -0800 post.ly has a nice UI http://weblog.smirnov.ca/postly-has-a-nice-ui http://weblog.smirnov.ca/postly-has-a-nice-ui

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Tue, 02 Feb 2010 06:15:29 -0800 Art of Paper Folding http://weblog.smirnov.ca/art-of-paper-folding-0 http://weblog.smirnov.ca/art-of-paper-folding-0

   

One Dollar      Butterfly
 
0mail_attachment
 

One Dollar        Camera
   

Two Dollars             Battle Tank
   

Two Dollars        Chinese Dragon
   

One Dollar Crab
   

One Dollar        Dolphin
   

Two Dollars   Jacket
   

Two Dollars       Spider
   

One Dollar         Scorpion 
One Dollar       Bat
   
One Dollar     Toilet Bowl

One Dollar      Penguin
 
12mail_attachment
 

One Dollar      Shark
   
One Dollar     Jet
   
One Dollar         Hammer Head Shark
   


Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Wed, 30 Dec 2009 06:58:30 -0800 Pictures http://weblog.smirnov.ca/pictures-1427 http://weblog.smirnov.ca/pictures-1427

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Fri, 13 Nov 2009 07:09:37 -0800 Writing Great Documentation http://weblog.smirnov.ca/writing-great-documentation http://weblog.smirnov.ca/writing-great-documentation Jacob Kaplan-Moss, co-author of Django and it's excellent excellent documentation writes a series titled Writing Great Documentation.

"This advice will mostly be targeted towards those documenting libraries or frameworks intended for use by other developers, but much of it probably applies to any for of technical documentation."

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov
Fri, 25 Sep 2009 08:25:00 -0700 There are Over a Million People Actively Using Facebook Right Now http://weblog.smirnov.ca/there-are-over-a-million-people-actively-usin-1 http://weblog.smirnov.ca/there-are-over-a-million-people-actively-usin-1 A great and refreshing perspective to evaluate services by the number of people who actually use it. Key point: "there are 1.6 to 6 million people actively using Facebook right now."

So Facebook is a "communication platform", right? If so, I can't help, but contrast this number with with the amount of people who are using email for one-to-many communications. I'm not even talking about one-to-one forms of communications such as SMS and voice.


A little over a week ago Facebook reached a major milestone: 300 million active users. The fastest-growth region continues to be Asia, but growth in other overseas regions such as the Americas and Africa have also been strong. Currently reaching only 1% of potential users in Asia and Africa, Facebook has barely scratched the surface in both regions:


pathint


Growth in the U.S. remains fastest among those age 45 and older, and the share of those users is higher in the U.S. than overseas. In other regions recent growth tended to be more evenly divided among age groups. One notable exception has been the teen group in Asia, which grew over 80% in the last 12 weeks.


pathint

Of the 300 million users, how many are actively using Facebook right now? (For the rest of this post active means not just logged in, but actually engaged.) By treating the previous question as a Fermi problem†, I can probably derive a decent estimate. First, I assume that the average fraction of people actively using Facebook at any moment, equals the fraction of time an average Facebook user is active on the site††. Without access to any usage stats, I'll throw out the following guesstimate: a typical Facebook user spends 4 hours per month (or 48 per year) actively using the site.

pathint

Depending on how accurate you want to be, there are 1.6 to 6 million people actively using Facebook right now. If the average Facebook user spends considerably more than 4 hours per month (actively) using the site, the estimate would be much higher than a 1.6 million. I do have an escape clause: in classic Fermi problems, being within a factor of 10 is considered acceptable.

(†) Increasingly popular in the business world, Fermi problems have long been staples in Physics (and Math) departments.
(††) In other words, if the average Facebook user spends 1% of her time actively using the site, on average 1% of all Facebook users are actively using the site at any given moment.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/184229/me.png http://posterous.com/users/eMBeTIheBb Alexis Smirnov Alexis Alexis Smirnov