<?xml version="1.0" encoding="UTF-8"?>
<feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:thr="http://purl.org/syndication/thread/1.0"
  xml:lang="en"
   >
  <title type="text">Antoine Leclair's Blog</title>
  <subtitle type="text">This is my blog</subtitle>

  <updated>2016-05-06T03:55:21Z</updated>
  <generator uri="http://blogofile.com/">Blogofile</generator>

  <link rel="alternate" type="text/html" href="http://antoineleclair.ca" />
  <id>http://antoineleclair.ca/feed/atom/</id>
  <link rel="self" type="application/atom+xml" href="http://antoineleclair.ca/feed/atom/" />
  <entry>
    <author>
      <name></name>
      <uri>http://antoineleclair.ca</uri>
    </author>
    <title type="html"><![CDATA[Eliminating Distraction]]></title>
    <link rel="alternate" type="text/html" href="http://antoineleclair.ca/2016/03/07/eliminating-distraction/" />
    <id>http://antoineleclair.ca/2016/03/07/eliminating-distraction/</id>
    <updated>2016-03-07T13:00:00Z</updated>
    <published>2016-03-07T13:00:00Z</published>
    <category scheme="http://antoineleclair.ca" term="Uncategorized" />
    <summary type="html"><![CDATA[Eliminating Distraction]]></summary>
    <content type="html" xml:base="http://antoineleclair.ca/2016/03/07/eliminating-distraction/"><![CDATA[<p>These days, I'm putting a lot of efforts in <a href="http://grawl.it">Grawl</a>, a side
project I had left aside and decided to revive. You can read more context in my
previous post:
<a href="/2016/02/09/on-my-way-to-100-paying-customers/">On My Way to 100 Paying Customers</a>.</p>
<p>The main difference with this new project is that I've decided to do it alone.
No other developer, no designer, no marketer, no seller, etc. I have to do it
all by myself.</p>
<p>While it has a lot of advantages, doing things alone require a lot more time.
Especially when I'm doing tasks in areas where I'm less comfortable, like
marketing. Also, because I'm alone, it's tougher to make decisions, because I'm
the one asking and answering the questions.</p>
<p>As it's still a side project, and freelancing is still where my income comes
from, I have to minimize distraction in order to keep things moving.</p>
<h2>Selling My Shares of Signsquid</h2>
<p>As you may know, I'm one of the cofounders of
<a href="https://signsquid.com">Signsquid</a>, an electronic signature SaaS. We first
created that application around 2011. We were 6 cofounders with a lot of
enthusiasm. To this day, I still had my shares in that project, which means
that I had to do some level of support.</p>
<p>Lately, it required more and more support time, and I did not believe that
the team, as it was before I sold my shares, would be able to bring that SaaS
to a level where we can say it succeeded. I did not consider that the time I
put in support was an investment. So, I decided to sell my shares to the other
guys. Which in turns, motivated other cofounders to rethink their involvement
in the project and also sell their shares. The new team is now much leaner and
in a better place to succeed.</p>
<p>On my side, I feel really relieved of what became a burden.</p>
<p>I can now focus on my current projects, which have more chances to succeed, and
are also much more fun.</p>]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://antoineleclair.ca</uri>
    </author>
    <title type="html"><![CDATA[Building Things Properly]]></title>
    <link rel="alternate" type="text/html" href="http://antoineleclair.ca/2016/02/23/building-things-properly/" />
    <id>http://antoineleclair.ca/2016/02/23/building-things-properly/</id>
    <updated>2016-02-23T12:00:00Z</updated>
    <published>2016-02-23T12:00:00Z</published>
    <category scheme="http://antoineleclair.ca" term="Uncategorized" />
    <summary type="html"><![CDATA[Building Things Properly]]></summary>
    <content type="html" xml:base="http://antoineleclair.ca/2016/02/23/building-things-properly/"><![CDATA[<p>As I'm working on <a href="http://grawl.it">Grawl</a> to push it to MVP, I thought I would
share some thoughts about building things properly.</p>
<h2>The Client That Wanted an MVP</h2>
<p>A few months ago, a prospect client asked for an estimate to build an MVP.
That MVP would have access to users bank accounts and be able to perform real
ACH transactions on their behalf.</p>
<p>The client wanted to build something extremely quickly to be able to prove the
market fit of his idea, which really does make sense. So I crafted an estimate
that would include the desired minimal feature set. He was surprised by the
amount of time needed to build that MVP (a few weeks).</p>
<p>For many reasons, I think he is a smart guy with a great business idea.
However, he had some misconceptions about what it means to build a web
application.</p>
<p>For a lot of people, the difference between a website and a web application can
be unclear, and that's really understandable! I have to explain it from time
to time to clients, friends and family members.</p>
<p>So, that client asked for some explanation. Why would it take so much time to
develop his app?</p>
<h2>A Website vs An Application</h2>
<p>First of all, let me explain some differences between a website and a web
application. You can use both through your web browser, like Chrome, Safari or
Internet Explorer, but conceptually, they are not the same.</p>
<h3>A Website Is&hellip;</h3>
<p>&hellip; content that you consume, that you read. Here are some examples:</p>
<ul>
<li>A restaurant's website where you can lookup the menu and the phone number.</li>
<li>A furnitures factory's website where you can see a list of what they make,
   how to apply for a job, phone numbers of each departments, etc.</li>
<li>A blog or a newspaper's website, where you can read articles.</li>
</ul>
<h3>A Web Application Is&hellip;</h3>
<p>&hellip; software that you can use to do things. In most cases, you can log in.
Here are some examples:</p>
<ul>
<li>A timesheet software where you can enter the time you worked at your day
   job.</li>
<li>A to-do application, where you add tasks that you have to
   do, and check tasks that you have done.</li>
<li>A bank's web application where you can log in, see your latest transactions,
   send money to someone, pay invoices.</li>
</ul>
<h3>The Line Is Blurry</h3>
<p>It's not always super clear. Here are some examples where the line is blurry:</p>
<ul>
<li>You can reserve a table at a restaurant using their website, this is handled
   by software.</li>
<li>Some administrator has to log into a content management system (CMS) to
   add/edit/remove content from the furniture factory's website.</li>
<li>A user can log in the newspaper's website and post comments to articles.</li>
<li>The bank has a regular website, where it showcases it's product. On the top
   right corner of the page, it says that "You are logged in as Antoine
   Leclair", which has to come from the application.</li>
</ul>
<h2>Developing a Web Application Is Not Developing a Website</h2>
<p>The lifecycle of a website is not the same as the lifecycle of a web
application.</p>
<h3>The Lifecycle of a Website</h3>
<p>The lifecycle of the code base of a website is similar to a brochure. Some
process (meetings, design, production, etc.) leads to a final product. The
brochure is printed, ready to be read. The website is online ready to be read.</p>
<p>At some point in the future, it will get too old. A new one will be produced.
The same process starts over (meetings, design, production, etc.). The new one
is ready, the old one is discarded.</p>
<p>The code base of the website during his whole life will not change much. A new
social network appears, we must add an icon. The client did not realize he
needed a page that let people know how to get to the factory, a new page must
be added, with a new link to that page on  the home page. If the content has to
be changed (more articles in a blog, new products in the catalog), the code
base will rarely change. The changes will rather be done in the CMS without
touching the code base.</p>
<p>You rarely find bugs in a website because the code is simple: it gets data from
a database and shows it in a page, it affects how things are presented (the
color for example), it performs simple animations. If there are any bugs, they
are generally really simple to fix and deploy. Even someone unfamiliar with
the code base will be able to do it easily.</p>
<h3>The lifecycle of a Web Application</h3>
<p>The lifecycle of the code base of a web application is extremely different. It
really is a software dressed like a website.</p>
<p>You can rarely foresee every aspect of a software before actually using it.
There's no solution, it's like that. Software is intangible. Talking about it
without touching it only make things worse. So, the way successful software is
generally done is by delivering the minimal feature set that has value for the
users, and then augmenting/changing that feature set as time goes.</p>
<p>It is rarely a better idea to create a new version of a software and discard
the old one. For example, if you discover that your timesheet application would
also need to do some accounting and that users should have the ability to add
details about the hours worked, those features will be added to the existing
application, instead of creating a new application.</p>
<p>This requires a code base that is evolvable.</p>
<h2>Some Considerations When Building a Web Application</h2>
<h3>Automated Testing</h3>
<p>In order to make the code base elvolvable, the first thing that comes to my
mind is <em>automated testing</em>. There are many types of automated testing: unit
testing, functional testing, integration testing&hellip; I won't go into the
details of each type. Some types of testing may be more appropriate than others
depending on the project.</p>
<p>An automated test is code that will reproduce a use case in an automated
manner and verify the result is correct. It could be code that tests that when
feeding <code>10</code> to the function <code>compute_taxes</code>, it actually returns <code>1.52</code>.
Or it could be remote controlling a real browser to simulate that a user logs
in, fills his daily timesheet then logs out, making sure that the changes were
saved correctly and the side effects (update a report, etc.) were done
properly.</p>
<p>To someone not familiar with writing software, it may seem like trivial test
examples that do not really add value. I'll give you some examples where those
tests will come in handy.</p>
<ul>
<li>
<p>Three years after the software has initially been deployed, and the
   person that wrote that code does not work there anymore, the business
   expands and the function <code>compute_taxes</code> must be updated to compute the
   taxes according to the state where the product is sold. Instead of receiving
   only <code>10</code>, it will also receive <code>NY</code> or <code>CA</code>, and the function should return
   the tax amount according to the state. You can update the existing tests to
   include the state that was implied before (for example, <code>CA</code>), that make
   sure the working case still works after the modification, then add new tests
   to also test other states. The developer does not have to manually test each
   cases. He just runs the tests, and that way, he is sure all the application
   still works correctly.</p>
</li>
<li>
<p>A bug report comes in. The taxes for <code>NY</code> are not computed correctly. If the
   code base is not covered by tests, the developer will look at the code, fix
   the bug, and test the application manually to see if the bug from the report
   he received is now fixed. It seems to be fixed, so he pushes his change in
   production. But by fixing the bug, he also introduced another subtle bug,
   that made the tax calculation wrong for every other state. If the code base
   is covered by test, the developer can run the test suite and catch the error
   right away. Also, since there was a bug in the first place, the developer
   will write a new test to make sure this bug never comes back.</p>
</li>
<li>
<p>A new requirement is that the timesheet includes a new box to enter
   the overtime, separated from the regular time. The existing browser test
   should still work. It may look like a very simple change, but it's often in
   those unexpected cases that something breaks somewhere else. In this
   example, loading the reports could make the application crash. The browser
   test will find it really fast.</p>
</li>
</ul>
<p>As most bugs are discovered as the code is being written, instead of receiving
bug reports, fixing them as they are introduced is much faster. Also, the test
suite is there to catch other bugs that the fix could introduce.</p>
<p>To summarize, automated testing really helps to keep a code base evolvable.</p>
<h3>Pre-made modules</h3>
<p>When building a website, pre-made modules/plugins are often useful. Need to
create an animated slideshow? There's a jQuery plugin for that. Need a private
section on your website where only authenticated users can upload files?
There's a WordPress plugin for that.</p>
<p>When building a web application, using those pre-made modules is often not the
optimal solution for many reasons.</p>
<ol>
<li>While it's normally accepted to adapt the requirements of a website
    according to what the existing plugins can do, it's normally not the case
    for a web application. For example, it could be important that a user
    provide his mobile phone number while signing up, but the existing modules
    do not ask for that information.</li>
<li>The requirements of a website will rarely change over time. If they change,
    there are good chances that a new website will be built to replace the old
    one. The requirements of an application do change. If a pre-made "users"
    module was used, to allow users to authenticate and access a private area,
    when the requirements change (they will), it could put you in a place where
    you can't modify the application to add the new behaviors. For example,
    when first writing the application, we did not need to ask for the phone
    number during signup, but two years later, we need that information to send
    an SMS near the end of the signup process, but the module that was used
    does not allow it.</li>
<li>It's often really hard to incorporate the pre-made modules into a complete
    test suite. They generally lack the access points that would be needed to
    test correctly, in the context of your application.</li>
<li>Using pre-made modules is often more about hacking the module to make it
    work in your context. Hacking code together to ship a website is perfectly
    acceptable. Doing the same for an application will make very brittle code,
    with really big consequences.</li>
</ol>
<p>When building a website, it makes sense to use those modules because it makes
it so much faster to ship! Not using it could mean 10x more time needed. Since
you don't need to maintain that code, you would rather code 9 new websites over
time than investing time in the first one to make it really maintainable by
writing custom code. The first one will be thrown away in 2-4 years anyway.</p>
<p>When building a web application, you can't afford to lose the
flexibility that pre-made module will take away from you. It could be
acceptable in some cases, but probably never in core parts of the application.
For example, if there is an animated slideshow in the application, it's
probably OK to use that jQuery plugin. Replacing it with another one in the
future will be easy since there is nothing that really depends on it.</p>
<p>However, using pre-made "users" modules, or "administration area" modules, is
often a really bad idea when building software, because it will lock you in
using those modules forever, with their limitations.</p>
<h3>APIs and Mocking</h3>
<p>When building websites, we sometimes have to access external APIs (data access
points that software can use). Most of the time, for a website, it is very
straightforward:</p>
<ul>
<li>Fetching the latest tweets of a user and displaying them on a page.</li>
<li>Getting the latest value of a stock and displaying it on a page.</li>
<li>Getting the weather forecast of a city and displaying it on a page.</li>
</ul>
<p>You get the pattern: read data from one access point, output it on a page in
the desired format. Even better: there are often libraries or code examples
that do the data-fetching for you. Copy-paste and tada!</p>
<p>When building a web application, the consumption of those APIs are generally
not that straightforward.</p>
<ul>
<li>There are often many calls to perform in a sequence.</li>
<li>Data has to be saved in the database.</li>
<li>That data in the database has to be architected to fit the exact business
   needs of the current application. For example, if a user enters a credit
   card (that is submitted to an external API), in your exact business needs,
   that credit card could be associated to a group of users, even if in the
   external API it's associated to only one user.</li>
<li>The API is only a data-access layer. It's very easy to do one API call. But
   it requires time to code all the meat around it. For example, if a user
   entered a credit card to subscribe to your service, it would probably mean
   that you have to keep track of the payments received for that user, and
   keep the user account active as long as the payments allow it. That means
   doing something special when the account becomes inactive. Also, what do
   we do when that card has expired? What do we do when a payment fails?</li>
<li>Since we are generally also sending data, there are generally error cases
   that have to be handled. The user entered a wrong credit card number, we
   have to tell the user that something failed.</li>
<li>External APIs will also want to tell your application about events that
   happen. You will have to write code that listen to those events and do
   something about them. For example, a user subscribed to your services using
   his credit card. You'll have to listen for successful payments to increase
   the duration of the subscription of the user.</li>
<li>A call to an API could fail because the external provider is down, or there
   is a network problem. You generally have to handle it in more complicated
   ways than "just hide the tweets if you can't read them", as you would do on
   a website.</li>
</ul>
<p>Also, since those APIs are external services, it can be hard or impossible to
write automated test suites (see above) that incorporates them. There are few
reasons for that:</p>
<ol>
<li>Every time you begin each of the automated tests, you have to be able to
    reset the environment to some initial known state. For example, if you had
    a test where a user logged in, added time to his timesheet, then looked at
    the updated report, you have to be able to reset the hours to some initial
    state before the test. Otherwise, every time you run the test, one more
    entry would be added, and the updated report would be unusable for testing
    because you will not be able to make sure that the last x hours have been
    entered, because they are already there 240 times from the previous runs of
    the tests. You need to be able to reset the state. External APIs often do
    not have that ability. They sometime only offer a sandbox where you can't
    reset the state to an initial condition.</li>
<li>Some API providers don't even offer a sandbox. It means all the calls that
    your application will do, even during testing, will be made against the
    live systems. It's impractical for some, if not most, testing. For
    example, you would have to submit a real credit card number and do real
    transactions on it. Every time you run the tests. Which is many times a
    day.</li>
<li>The external API sandboxes are extremely unreliable. They are often
    offline, the provider closes your sandbox account or changes your settings
    without telling you, they are testing new features that breaks the old
    ones, etc.</li>
</ol>
<p>Since you can't include them in your tests directly, you have to create
something that behaves like them for the context of the test cases. It's called
a "mock". During the tests, your application will talk with that mock instead
of talking with the real API endpoint. It's a mini-version of the external
service. For example, if you mocked a payment provider, it could accept all
credit card numbers except for one, that will be used for testing when the user
enters an invalid number. The payments could always work for all credit cards
but one number, where the payments always fail. Or it could refuse payments
of 29.99 on one specific card number. Or it could only allow for 2 payments of
29.99 on one specific credit card number, then bounce the next ones.</p>
<p>Since you wrote that mock and you host it, you have complete control over it:</p>
<ul>
<li>It will always be online when you need it.</li>
<li>You can reset it when you want.</li>
<li>The reset you apply brings the state to the exact case that you need.</li>
<li>You can simulate specific use cases e.g. two payments that works,
   then a third one that fails, etc.).</li>
</ul>
<p>Those mocks are really needed and are really useful, but they also take time to
write.</p>
<h3>Deployment</h3>
<p>Deploying a website is generally done by uploading the new files to the server
that hosts those files. The developer sees that it looks good on when he worked
on it on his laptop, then he uploads it. Or even faster, some directly edit the
files on the production server.</p>
<p>Deploying a web application is generally more involving. You push your work in
a source code repository (think GitHub), a continuous integration (CI) server
builds the source (more on that below), runs all the tests, and allows you to
deploy if all the tests are green. Doing the setup of the CI server (how it
pulls the code from the repository, how it builds, how it runs the tests, how
it deploys) requires some time.</p>
<p>Also, there's often a staging server to maintain, where a copy of the
application is running fake accounts. That way, you can demo new changes for
approval without deploying to the production server.</p>
<p>You must use those good practices when developing an application because
otherwise, bugs that did not occur on the developer's laptop emerge in
production. The exact source of the bugs is always a surprise, but it includes:</p>
<ul>
<li>The timezone was not the same on the developer laptop and on the production
   server.</li>
<li>The developer runs Mac OS X or Ubuntu, but the production server runs
   another operating system, like Debian.</li>
<li>The developer has a library installed on his laptop, but it's not installed
   on the production server. This allowed the developer to scale an image on
   his laptop, but doing the same thing on the production server crashes.</li>
</ul>
<h3>Database Migrations</h3>
<p>When a website has been deployed, it rarely happens that the database schema
will change. For example, it will rarely happen that, suddenly, you need
captions in the pictures of the slideshow, while you did not need it when the
website was first published. Also, when that happens, you can connect to the
database, write the command that adds the new column, and execute it.</p>
<p>For an application, a change to the database schema is everyday life. But,
unlike the website, you can't just connect to the database and write some
commands. It needs to be executed in a reproducible manner. Some reasons are:</p>
<ul>
<li>More than one person may work on a project. Everyone has to keep their
   schema up-to-date.</li>
<li>There are more than one server to apply the changes: production, staging,
   etc.</li>
<li>The changes has to be tested before they are executed in production. Some
   changes may fail or have unwanted behaviors. This has to be correct
   the first time it runs in production.</li>
<li>Many different features may be developed at the same time in parallel. The
   database schema has to match the current branch of the code. In order to do
   that, you have to apply changes and also be able to apply the reverse of
   those changes easily when you change branch.</li>
</ul>
<p>This is why we need database migrations: a system to do database schema changes
in a reproducible manner. The simplest form could be a folder containing SQL
files. But it's generally in the form of code that apply those migrations for
you when you ask for it.</p>
<p>Doing the setup of the migration system and writing proper migrations is
another task that requires time and is not needed when building a website.</p>
<h3>Compiled and Minified Resources</h3>
<p>When building a website, you may want to minify your resources. That means that
you take your JavaScript and CSS (style sheets) and use a minifier that will
reduce the size of those files by using many strategies, like change long
variable names like <code>numberOfChildren</code> to <code>b</code> and removing line breaks. Also,
there are new languages that developers sometimes prefer to use instead of
JavaScript and CSS, that will be compiled by a compiler to become JavaScript
and CSS. CoffeeScript and SASS are two examples. When you build a website,
building those resources is something that could be done manually. For example,
just before you deploy, you minify all your resources by using the command
line.</p>
<p>When building a web application, that process has to be automated. Some reasons
are:</p>
<ul>
<li>You do not simply copy your code to the server when you want to deploy
   (see deployment above). Some other server will deploy for you.</li>
<li>The code is kept under source control. When the code is compiled and
   minified, it's generally on one single line, which means that the whole file
   that contains all of your JavaScript changes every time you change one
   single character in one of your file. This result if huge changes in every
   commit, which makes the repository bigger (takes longer to clone) and harder
   to understand.</li>
<li>The minified version also needs to be tested by the CI server.</li>
<li>The version deployed has to be the one tested on the CI server.</li>
<li>The code changes a lot. Building the minified files manually every time
   would not make sense.</li>
</ul>
<p>Doing the setup of the automated minification/compiling is something that also
requires time and could be skipped when building a website.</p>
<h2>The Discardable Prototype To Test Market Fit</h2>
<p>Until now, I talked about a website vs a web application. I used the website
comparison, but it could probably also be valid with a prototype application
that you only want to use to discover if your idea has a market fit.</p>
<p>If you intend to throw away your prototype application right after you
discovered if your idea has, or not, a market fit, you could consider
prototype applications to have the same characteristics that a website would
have. In theory that is true. You will never need to maintain the code, so you
don't have to bother about making it evolvable.</p>
<p>However, there are some more considerations before you can go that path.</p>
<p>First, it's really easy to fall in the trap of thinking that you will discard
your prototype application really soon. In practice, the code base rarely gets
thrown away. A total rewrite is extremely rare. The shortcut you take now will
stay with you for a really long time. It will cost you money and agility.</p>
<p>Second, it's not always possible to do a quick prototype like that. I'm going
back to the example I started with: the client wanted an application that would
have access to users' bank accounts, see transaction history and other data and
perform ACH transactions. This is a case where the application will store
really sensitive data and would be able to perform really sensible operations.
A bug or a security breach would be a disaster for the users, the client,
the developer and everyone in between. In those cases, you have to write
reliable software. That means using the best practices mentioned above, like
automated testing.</p>
<h2>Back to Grawl</h2>
<p>Like I was saying in the introduction, I'm currently pushing
<a href="http://grawl.it">Grawl</a> to bring it to an MVP level. In this case, I'm my own
client. I would really like it to get there faster.</p>
<p>I'm currently writing the code that handles the credit cards. It seems quite
simple at first, but a lot of use cases have to be covered by the automated
tests. Otherwise, I could be charging too much to someone, leak private data,
allow someone to use the application without paying the correct amount, etc.</p>
<p>It takes time.</p>
<p>But building that part properly is <strong>required</strong>. That's not an optional
feature.</p>
<h2>In Summary</h2>
<p>This was a super long article, but I think writing a shorter one would not have
covered enough to be taken seriously.</p>
<p>Building software the right way requires time, but everyone wins in the end.</p>]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://antoineleclair.ca</uri>
    </author>
    <title type="html"><![CDATA[On Entrepreneurship Coaches]]></title>
    <link rel="alternate" type="text/html" href="http://antoineleclair.ca/2016/02/16/on-entrepreneurship-coaches/" />
    <id>http://antoineleclair.ca/2016/02/16/on-entrepreneurship-coaches/</id>
    <updated>2016-02-16T15:00:00Z</updated>
    <published>2016-02-16T15:00:00Z</published>
    <category scheme="http://antoineleclair.ca" term="Uncategorized" />
    <summary type="html"><![CDATA[On Entrepreneurship Coaches]]></summary>
    <content type="html" xml:base="http://antoineleclair.ca/2016/02/16/on-entrepreneurship-coaches/"><![CDATA[<p>Last week, I read this article: <a href="https://www.entrepreneur.com/article/254509">'I Will Teach You To Be Rich.' Here's How One Man Continues to Make Good on That Promise</a>.</p>
<p>If you don't have time to read, the <em>tl;dr</em> is that it gives three examples of
people who succeeded using Ramit Sethi's course.</p>
<p>By reading in diagonal, it looks great. But looking closer, they all became
coaches and that's how they make money.</p>
<p>Sounds like:</p>
<p>&mdash; Give me 1000$ and I'll teach you how to make money.
<br>
&mdash; OK, here's your 1000$.
<br>
&mdash; See, that's how I make money.</p>
<h2>What Have YOU Done?</h2>
<p>When you start a business, one of the things people do is networking. Not like
<em>Linkedin networking</em>, but meeting real people in cocktails and events. You soon
realize that some people play the game of looking successful in the hope of
bringing success.</p>
<p>This type of people, I'm sure there's a name for them, are also often involved
as judges and mentors in startup competitions, hackathons, etc. They can be
very convincing when giving tips.</p>
<p>But, how can they teach something useful if they have never been successful
themselves?</p>
<p>If you are starting in business, it's important to be aware of that type of
people. They may look like they can help you, but in reality, they will just
consume your time.</p>
<p>Asking the opinion of prospect clients is probably 1000x more productive than
to ask those coaches.</p>
<p>To be clear, this is not a rant against Ramit Sethi. I have not read his book
nor taken his course. I don't even know how successful he was before being
coach. As far as I know, his book is about personal finance and not directly
about entrepreneurship.</p>]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://antoineleclair.ca</uri>
    </author>
    <title type="html"><![CDATA[On My Way to 100 Paying Customers]]></title>
    <link rel="alternate" type="text/html" href="http://antoineleclair.ca/2016/02/09/on-my-way-to-100-paying-customers/" />
    <id>http://antoineleclair.ca/2016/02/09/on-my-way-to-100-paying-customers/</id>
    <updated>2016-02-09T12:00:00Z</updated>
    <published>2016-02-09T12:00:00Z</published>
    <category scheme="http://antoineleclair.ca" term="Uncategorized" />
    <summary type="html"><![CDATA[On My Way to 100 Paying Customers]]></summary>
    <content type="html" xml:base="http://antoineleclair.ca/2016/02/09/on-my-way-to-100-paying-customers/"><![CDATA[<p><em>tl;dr I've decided to put the efforts <a href="http://grawl.it/">Grawl</a> deserves.
<a href="http://grawl.it/">Grawl</a> is a crawler that finds broken links on your
websites and alerts you.</em></p>
<h2>A Two Year Pause</h2>
<p>I've been extremely busy over the last two years. I have been freelancing with
<a href="http://www.10xmanagement.com/">10x Management</a>. They bring me a lot of fun
projects to work on, they are awesome! I also had a baby, she turned 2 a few
days ago. For those who have had babies, you understand how time consuming it
can be! I also spent about a year in Spain, which implies first moving to
Spain, and then moving back to Canada.</p>
<p>During those two years, I have put aside pretty much every other projects I
had. Building robots and electronic projects, playing music, doing
kung fu, building startups.</p>
<p>But now! It's time to get back to building startups!</p>
<p>As some of you may know, in the past, I cofounded
<a href="https://signsquid.com/">Signsquid</a>, an electronic signature web application.
I was also part of the early days of <a href="https://snipcart.com/">Snipcart</a>,
an HTML and JavaScript shopping cart, which is really taking off!</p>
<p>I'm a software developer, so when I was part of those projects, I was
mostly concerned with the technical aspect. I've never spent much time doing
the business part: marketing, closing deals, etc. I've always lived with the
idea that I could not do it myself, that I needed other cofounders to do it.
But these days are over!</p>
<p>Now, I'm not saying that I'm not welcoming a business guy as a cofounder! I'm
saying that I don't want to wait for the perfect cofounder.</p>
<h2>Grawl, The Project That Needed Some Love</h2>
<p>Last week, I've read a blog post by Nathan Barry. It's called
<a href="http://nathanbarry.com/quit/">Knowing When to Quit</a>. To summarize a little
bit, he says that when a project is just sitting there and doing nothing,
you should either kill it or give it the effort it deserves. It's really a
great blog post that inspired me, because I have this project I did back in
2012-2013.</p>
<p><a href="http://grawl.it/">Grawl</a>.</p>
<p>It was never quite the MVP I needed to test the market fit. It was abandoned.
Here's a screenshot of how it looks like today (February 2016) and have been
for the last few years:</p>
<p><a href="http://grawl.it/"><img src="/content/20160209/grawl-screenshot.png" "Grawl as it is today (February 2016)"></a></p>
<p>Grawl, at its heart, is a SaaS that will find broken links on your websites.
For example, it will find links that point to 404. The main difference with
existing tools, like Google Webmaster Tools, is that Grawl will keep the list
of websites you have and alert you by email when it finds broken links. It
crawls all of your websites every months and it sends you an email when it's
done. Also, since it's a specialized tool for broken links, it opens the door
to cool features, like providing an actionable checklist of all the links to
fix, etc.</p>
<p>It's not revolutionary, but I'm sure it has value for someone. Agencies?
Big website maintainers?</p>
<h2>The 100 First Paying Customers</h2>
<p>At the time of writing, there are 11 users in the database. Mostly people that
I told about the project in 2012-2013. We could say 0. Also, since there
is currently no way to get a paying account, they are not paying customers.</p>
<p>Let's change that.</p>
<p>My first few steps toward my goal of getting 100 paying customers will be:</p>
<ul>
<li>Update the code base and infrastructure to 2016 (more on that below).</li>
<li>Add the ability to charge customers: plans, credit cards, etc.</li>
<li>Build a real MVP website.</li>
</ul>
<p>After that, I will be ready to attack the market.</p>
<p>Regarding updating the code base to 2016, I don't plan to rewrite anything.
It's easy to fall in the trap of changing framework for the <em>goût du jour</em>
framework. Here I'm talking about fixing stuff that broke over the few years
the project was abandoned, updating libraries version, having proper backups,
etc.</p>
<h2>In Summary</h2>
<p>This post is more or less the kickoff of my efforts to bring a new SaaS to its
first 100 paying customers. I'll try to post a lot more often, about the
progress, the strategies, the success and failures. Stay tuned!</p>]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://antoineleclair.ca</uri>
    </author>
    <title type="html"><![CDATA[Using An Arduino As External Oscillator For An AVR Chip]]></title>
    <link rel="alternate" type="text/html" href="http://antoineleclair.ca/2014/08/27/using-an-arduino-as-external-oscillator-for-an-avr-chip/" />
    <id>http://antoineleclair.ca/2014/08/27/using-an-arduino-as-external-oscillator-for-an-avr-chip/</id>
    <updated>2014-08-27T14:30:00Z</updated>
    <published>2014-08-27T14:30:00Z</published>
    <category scheme="http://antoineleclair.ca" term="Uncategorized" />
    <summary type="html"><![CDATA[Using An Arduino As External Oscillator For An AVR Chip]]></summary>
    <content type="html" xml:base="http://antoineleclair.ca/2014/08/27/using-an-arduino-as-external-oscillator-for-an-avr-chip/"><![CDATA[<p>As you may know, I am currently a freelance software developer. <a href="http://hooba.ca">I write code for a living</a>. However, I am more and more intereseted in building things that are not emprisoned in a screen. I've been playing with Arduino for a while now and I thought I would try using the AVR chips directy instead of relying on Arduino.</p>
<p>So I bought a few ATmega168's on ebay and an <a href="http://www.fischl.de/usbasp/">usbasp</a>. Well, a cheap Chinese version of usbasp but it feels solid and is pretty small.</p>
<p><img src="/content/20140827/atmega168.jpg" alt="ATmega168"/></p>
<p><img src="/content/20140827/avrusb.jpg" alt="avusb"/></p>
<p>Then I decided to try my new things. I connected all the wires properly and plugged the usbasp in my laptop. I run Ubuntu 14.04 as I do this if that might help others in the future. First thing is to try to speak to the ATmega168:</p>
<pre><code>avrdude -p atmega168 -c usbasp
</code></pre>
<p>I got this error message:</p>
<pre><code>avrdude: Warning: cannot query manufacturer for device: error sending control message: Operation not permitted
avrdude: Warning: cannot query product for device: error sending control message: Operation not permitted
avrdude: error: could not find USB device with vid=0x16c0 pid=0x5dc vendor='www.fischl.de' product='USBasp'

avrdude done.  Thank you.
</code></pre>
<p>I guess I can change permissions later, but for now:</p>
<pre><code>sudo avrdude -p atmega168 -c usbasp
</code></pre>
<p>Little bit better, but still not working:</p>
<pre><code>avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: error: programm enable: target doesn't answer. 1
avrdude: initialization failed, rc=-1
         Double check connections and try again, or use -F to override
         this check.


avrdude done.  Thank you.
</code></pre>
<p>I looked all over the web trying to figure out what was going on. Turns out the cheap Chinese usbasp's have a firmware that does not allow to set manually the clock speed. It's automatic. So when avrdude tries to set the clock speed and the usbasp does not change it, it complains. But since it's automatic, it should not cause problem. You can always try to update the firmware of your usbasp, which should let you change the clock speed manually, but you'll loose the automatic and will always have to specify it.</p>
<p>Since the clock speed was not the problem, I double (triple, etc.) checked the connections. I found other diagrams for the pinout of the usbasp, where every pin is reversed, mirror style. But this is just because some diagrams show the pins as they come out of the usbasp and others show it as they come out of the ribbon cable connector. After trying to reverse a few times, I found out there was a red wire in the ribbon to indicate Vcc. OK, some might think I'm stupid but when you don't know... Anyway, all my connections were right in the first place and it was not the problem.</p>
<p>Then I remembered that Arduino chips have some fuses set so they use an external oscillator for their clock, instead the internal clock. When the fuses are set to use the external oscillator, the chip is dead without it. So I had a look at the ebay auction where I bought the ATmega168's, and it says they are preloaded with the Arduino bootloader. Crap. And I don't have an oscillator at hand.</p>
<p>By searching more, I found this <a href="http://www.avrfreaks.net/forum/tutsoft-recovering-locked-out-avr?name=PNphpBB2&amp;file=viewtopic&amp;t=106325">forum post</a>. If you run in the same problem, I suggest you read it.</p>
<p>Basically, I guess the best way would have been to use an oscillator, but he suggests a few other ways to hack something to replace the oscillator. He suggests using a 555 timer at around 1 MHz. I have all that is needed, but I would have to select the proper RC components and wire all that together. Time consumming and too demanding at 2 AM. The other solution, which is nice, is that you can use another AVR chip as a clock. All my ATmega168 have an Arduino bootloader, so I can't use them right now. But I have an Arduino Uno that is very easy to program. Just plug it in USB and use Arduino IDE to upload.</p>
<p>So the code looks like this:</p>
<div class="pygments_default"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;avr/io.h&gt;</span><span class="cp"></span><br/><br/><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span><br/>    <span class="n">DDRB</span> <span class="o">=</span> <span class="mh">0xFF</span><span class="p">;</span><br/>    <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span><br/>        <span class="n">PORTB</span> <span class="o">^=</span> <span class="mh">0xFF</span><span class="p">;</span><br/>    <span class="p">}</span><br/>    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span><br/><span class="p">}</span><br/></pre></div>

<p>I didn't translate it to Arduino, since it compiled and uploaded without complaining. You can connect any pin of PORTB of the Arduino (that is 8-13) to XTAL1 of the ATmega168.</p>
<p>I took the default fuses for ATmega168 of <a href="http://www.engbedded.com/fusecalc/">this calculator</a>.</p>
<pre><code>sudo avrdude -p atmega168 -c usbasp -U lfuse:w:0x62:m -U hfuse:w:0xdf:m -U efuse:w:0xf9:m
</code></pre>
<p>It worked and I can now program my ATmega168's. Hurray!</p>]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://antoineleclair.ca</uri>
    </author>
    <title type="html"><![CDATA[The Importance of Idempotence]]></title>
    <link rel="alternate" type="text/html" href="http://antoineleclair.ca/2014/08/15/the-importance-of-idempotence/" />
    <id>http://antoineleclair.ca/2014/08/15/the-importance-of-idempotence/</id>
    <updated>2014-08-15T03:40:00Z</updated>
    <published>2014-08-15T03:40:00Z</published>
    <category scheme="http://antoineleclair.ca" term="Uncategorized" />
    <summary type="html"><![CDATA[The Importance of Idempotence]]></summary>
    <content type="html" xml:base="http://antoineleclair.ca/2014/08/15/the-importance-of-idempotence/"><![CDATA[<p><em>tl;dr Idempotence helps create more robust systems.</em></p>
<p>Idempotence is a mathematical concept that should be understood by all developers.</p>
<p>An operation is considered idempotent when doing it more than once is the same as doing it once.</p>
<p>For example, multiplying by 1 is idempotent.</p>
<pre><code>x * 1 == x * 1 * 1
</code></pre>
<p>Multiplying by 0 is also idempotent.</p>
<pre><code>x * 0 == x * 0 * 0
</code></pre>
<p>The key concept to remember is that applying the operation once can have side effects, but applying it more than once will not do anything more that what was already done the first time.</p>
<p>Assignment is idempotent.</p>
<pre><code>x := 4
</code></pre>
<p>You can assign 4 to x as much as you want, x will still be 4. But assigning 4 to x one time is different than zero time.</p>
<h2>HTTP Verbs</h2>
<p>HTTP verbs can be classified as idempotent or not.</p>
<p><code>DELETE</code> is an idempotent verb. No matter how many times you do it after the first time, it will give the same result as the first time. For example, <code>DELETE /users/4/contacts/3</code> could remove your contact with the ID 3. If you call it again, that contact has already been removed and nothing more should happen.</p>
<p><code>GET</code> is also idempotent. In fact, it's more than idempotent. It is considered a safe method. Safe methods can be compared to multiplying by 1. Doing it zero, once or more times should have the same effect. All <code>GET</code> does is get a resource. For example, you should never use normal links to delete resources.</p>
<p><code>POST</code> is <strong>not</strong> idempotent. Every time you do it, you can expect a side effect to happen. For example, every time you <code>POST</code> a contact form, an email is sent.</p>
<p>When it comes to APIs, that concept is well understood by consumers and providers. Designing around it will result in <a href="https://en.wikipedia.org/wiki/Principle_of_least_astonishment">least astonishment</a>.</p>
<p>See Wikipedia: <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods">Safe Methods</a> and <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods_and_web_applications">Idempotent methods</a>.</p>
<h2>Message Queues</h2>
<p>Let's say you build a web app to manage events. You can add people to the invitees of an event. In other words, an event has many invitees. For quicker response time, you decided to send all emails from a worker. So when a user finalizes an event, a message is queued. A worker gets that message and sends the invite emails for that event.</p>
<p>This is a really common pattern, and if you are not doing it that way, you should really start to.</p>
<p>You realize that you had an SMTP problem and all your emails have not been sent for some time, and it's not even showing up in the logs! You think "oh, well, I'll just call the function to send the emails again", but you don't know for which events you should call that function.</p>
<p>Here comes idempotence.</p>
<h3>When you execute a task in a worker, always make sure it's idempotent</h3>
<p>For the email example, every time you send an email to an invitee, you can keep the datetime in the database, in the event invitee row. If it has already been sent (sent datetime is not NULL), don't send it again. As easy as that. Also, you might want to check if the event is finalized. If not finalized, do nothing.</p>
<p>More generally:</p>
<ul>
<li>Check that your job is ready to be executed (e.g. event finalized). If not, do nothing.</li>
<li>Check that the job has not already been done. If done, do nothing.</li>
<li>Do job, keep datetime or something else in the database, log that it has been done (e.g. "INFO Invitation email for event 234 has been sent to john.doe@example.com").</li>
<li>Keep jobs granular. You have 5 emails to send? Queue a job (e.g. <code>send_event_emails(event_id)</code>) that will queue the 5 other jobs (e.g. <code>send_event_email_to_invitee(event_id, invitee_id)</code>).</li>
</ul>
<p>You realize something went wrong? You can always call your function to send emails on all events. Still crashed when half of the emails were sent? Fix what was wrong and just call it again. Also, it's easy to inspect what emails have not been sent yet. Bonus, you can do some intelligence with the datetimes (how many emails a day do we send? what are the peak hours?).</p>
<p>Also, some message queues don't garantee that a message will be delivered only once. Amazon SQS is that way. Your workers should really only do idempotent tasks.</p>
<h2>SQL Migrations</h2>
<p>In the same spirit as the worker example above, when you do an SQL migration, do it in an idempotent way when possible.</p>
<p>For example, you decide to split the user table in two tables. One for basic informations (<code>users</code>) and one for all details that are not always important (<code>profiles</code>). You put a foreign key <code>user_id</code> in the <code>profiles</code> table. You have a migration that takes every row in <code>users</code> (<code>SELECT * FROM users</code>) and inserts a row in <code>profiles</code> with user data. You run it, and well, it crashes midway after 1 hour, because of some NULL value you didn't think about. You fix it and run it again, but you then realize that some users have already been processed and have two profiles.</p>
<p>The idempotent solution: instead of <code>SELECT * FROM users</code>, you can just select the users that don't have a profile row. That way you can run it as many times as you want. It will only process the few users that have not been processed yet. A big advantage of that method is that you can leave your app running in production while you do the migrations. When you are ready to deploy the new code that uses the <code>profiles</code> table, you can call your function again to make sure the latest users that signed up are also migrated. That example is not so great, because a user could change some information in the <code>users</code> table during the migration, but I guess you get the point.</p>
<h2>Denormalized Data</h2>
<p>You have an application where each user has many documents. They can search their documents by tags. Tags come from many sources. The title of the documents, the folders, actual tags, the names of the authors, etc. You decided to keep a table named <code>tags</code> where you keep all the tags for every documents, it looks like this: <code>id</code> (hash), <code>tag</code> (actual text of the tag), <code>document_id</code> (foreign key to the document). When you add an author to a document, it does an insert in the <code>tags</code> table. When you remove an author, it finds the good tag and removes it.</p>
<p>Someday, you see in the log there was an error every once in a while when inserting a tag because of an obscure character encoding issue. You fix the issue and deploy the new code. However, there are a lot of missing tags and you have no easy way to fix it manually.</p>
<p>Instead of just having functions of the type <code>add_tag_for_new_author</code>, you should have a function of the type <code>update_tags_for_document</code>. When you call that function, instead of just adding a tag for the author that was just added, it checks all the document, rebuilds the tags list and makes sure that the correct data is in the database. That way, the <code>tags</code> table is really managed as it should be: a cache. You could delete all rows from that table and just call <code>update_tags_for_document</code> on every documents. It takes 2s to update the tags for a document? Let the worker do it, queue a message.</p>
<h2>Conclusion</h2>
<p>If you were not aware of idempotence, I hope I convinced you to use it. Also, please note that I kept the examples simplistic for educational purpose.</p>]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://antoineleclair.ca</uri>
    </author>
    <title type="html"><![CDATA[Deploying a Pyramid App on AppFog]]></title>
    <link rel="alternate" type="text/html" href="http://antoineleclair.ca/2012/08/28/deploying-a-pyramid-app-on-appfog/" />
    <id>http://antoineleclair.ca/2012/08/28/deploying-a-pyramid-app-on-appfog/</id>
    <updated>2012-08-28T21:45:00Z</updated>
    <published>2012-08-28T21:45:00Z</published>
    <category scheme="http://antoineleclair.ca" term="Uncategorized" />
    <summary type="html"><![CDATA[Deploying a Pyramid App on AppFog]]></summary>
    <content type="html" xml:base="http://antoineleclair.ca/2012/08/28/deploying-a-pyramid-app-on-appfog/"><![CDATA[<p>Last July, <a href="https://www.ctl.io/appfog/">AppFog</a> revealed it's official plans, which include a free plan that comes with 2GB of RAM. I then decided to give it a try and move a Pyramid app that I had running on a VPS for about a year. The app uses Python 2.7, PostgreSQL, Pyramid 1.3.2 and SQLAlchemy 0.7.8.</p>
<p>On the VPS, the app was running using Waitress behind nginx.</p>
<p>I had to make some minor modifications to the code to make it run on AppFog, which were not really documented anywhere. I decided to post it here, in the hope someone finds it when needed.</p>
<h2>Configuration File</h2>
<p>First of all, I created a new configuration file. I named it <code>appfog.ini</code>, but name it whatever you like. I removed the key <code>sqlalchemy.url</code>, since it is set in environment variables by AppFog. Also, for the app to know that it has to retreive the environment variables instead of using <code>sqlalchemy.url</code>, I added the key/value <code>appfog = true</code>.</p>
<h2>SQLAlchemy Connection</h2>
<p>In <code>main</code> function of <code>__init__.py</code>, I replaced the line where the engine is created from the configuration file to take into account that the connection information could come from environment variables. So I replaced:</p>
<div class="pygments_default"><pre><span></span><span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">&#39;sqlalchemy.&#39;</span><span class="p">)</span><br/></pre></div>

<p>with:</p>
<div class="pygments_default"><pre><span></span><span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;appfog&#39;</span><span class="p">)</span> <span class="o">==</span> <span class="s1">&#39;true&#39;</span><span class="p">:</span><br/>    <span class="n">engine</span> <span class="o">=</span> <span class="n">appfog_engine</span><span class="p">(</span><span class="n">settings</span><span class="p">)</span><br/><span class="k">else</span><span class="p">:</span><br/>    <span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">engine_from_config</span><br/>    <span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">&#39;sqlalchemy.&#39;</span><span class="p">)</span><br/></pre></div>

<p>And I defined <code>appfog_engine</code> later in the same file:</p>
<div class="pygments_default"><pre><span></span><span class="k">def</span> <span class="nf">appfog_engine</span><span class="p">(</span><span class="n">settings</span><span class="p">):</span><br/>    <span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">create_engine</span><br/>    <span class="kn">import</span> <span class="nn">os</span><span class="o">,</span> <span class="nn">json</span><br/>    <span class="n">all_config</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;VCAP_SERVICES&quot;</span><span class="p">))</span><br/>    <span class="n">config</span> <span class="o">=</span> <span class="n">all_config</span><span class="p">[</span><span class="s1">&#39;postgresql-9.1&#39;</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;credentials&#39;</span><span class="p">]</span><br/>    <span class="n">connection_string</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;postgresql+psycopg2://</span><span class="si">%(username)s</span><span class="s1">:</span><span class="si">%(password)s</span><span class="s1">&#39;</span><br/>                        <span class="s1">&#39;@</span><span class="si">%(host)s</span><span class="s1">:</span><span class="si">%(port)d</span><span class="s1">/</span><span class="si">%(name)s</span><span class="s1">&#39;</span><span class="p">)</span><br/>    <span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="n">connection_string</span> <span class="o">%</span> <span class="n">config</span><span class="p">)</span><br/>    <span class="k">return</span> <span class="n">engine</span><br/></pre></div>

<h2>Requirements</h2>
<p>Like when you <a href="http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/deployment/heroku.html">deploy on Heroku</a>, you have to provide a <code>requirements.txt</code> file, that you generate by running:</p>
<pre><code>$ pip freeze &gt; requirements.txt
</code></pre>
<h2>WSGI App</h2>
<p>You then have to create a <code>wsgi.py</code> file that you place at the root of your project, beside <code>setup.py</code> and <code>appfog.ini</code>. In <code>wsgi.py</code>, you put:</p>
<div class="pygments_default"><pre><span></span><span class="kn">import</span> <span class="nn">os</span><br/><span class="kn">from</span> <span class="nn">paste.deploy</span> <span class="kn">import</span> <span class="n">loadapp</span><br/><br/><span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s2">&quot;python setup.py develop&quot;</span><span class="p">)</span><br/><span class="n">path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span><br/><span class="n">application</span> <span class="o">=</span> <span class="n">loadapp</span><span class="p">(</span><span class="s1">&#39;config:appfog.ini&#39;</span><span class="p">,</span> <span class="n">relative_to</span><span class="o">=</span><span class="n">path</span><span class="p">)</span><br/></pre></div>

<h2>That's It</h2>
<p>Your app is ready to upload using the regular instructions, using the <code>af</code> commmand line tool provided by AppFog.</p>
<h2>Useful Stuff</h2>
<p>Since my app was already in production for about a year, I had data in my PostgreSQL database that I had to migrate from my server to AppFog. One nice feature they provide is the ability to make a tunnel to your services. You can find the doc <a href="https://github.com/appfog/afdocs/blob/master/services/tunneling.markdown">here</a>. With the help of the tunnel, it was easy to use <code>pg_dump</code> and <code>psql</code> to migrate the database.</p>]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://antoineleclair.ca</uri>
    </author>
    <title type="html"><![CDATA[Generating Country List For HTML Select]]></title>
    <link rel="alternate" type="text/html" href="http://antoineleclair.ca/2011/12/13/generating-country-list-for-html-select/" />
    <id>http://antoineleclair.ca/2011/12/13/generating-country-list-for-html-select/</id>
    <updated>2011-12-13T23:25:00Z</updated>
    <published>2011-12-13T23:25:00Z</published>
    <category scheme="http://antoineleclair.ca" term="Uncategorized" />
    <summary type="html"><![CDATA[Generating Country List For HTML Select]]></summary>
    <content type="html" xml:base="http://antoineleclair.ca/2011/12/13/generating-country-list-for-html-select/"><![CDATA[<p>During a client project using Paypal DirectPayment API, I had to make a <code>&lt;select&gt;</code> with all the countries with their country codes as the value. For example:</p>
<div class="pygments_default"><pre><span></span><span class="p">&lt;</span><span class="nt">option</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;US&quot;</span><span class="p">&gt;</span>United States<span class="p">&lt;/</span><span class="nt">option</span><span class="p">&gt;</span><br/><span class="p">&lt;</span><span class="nt">option</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;CA&quot;</span><span class="p">&gt;</span>Canada<span class="p">&lt;/</span><span class="nt">option</span><span class="p">&gt;</span><br/></pre></div>

<p>Paypal already gives <a href="https://developer.paypal.com/docs/classic/api/country_codes/">this list</a>.</p>
<p>Problem is that it's only in English and all in caps. What I needed is a French version and an English version, not in caps.</p>
<p><a href="http://www.geonames.org/">Geonames.org</a> just happens to have what I needed. This Python script is what I coded to generate what I needed:</p>
<div class="pygments_default"><pre><span></span><span class="kn">import</span> <span class="nn">urllib</span><span class="o">,</span> <span class="nn">json</span><span class="o">,</span> <span class="nn">unicodedata</span><br/><br/><span class="k">def</span> <span class="nf">get_list</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s1">&#39;demo&#39;</span><span class="p">,</span> <span class="n">lang</span><span class="o">=</span><span class="s1">&#39;en&#39;</span><span class="p">):</span><br/>    <span class="sd">&quot;&quot;&quot;Fetches the json of all countries from geonames.org.&quot;&quot;&quot;</span><br/>    <span class="n">params</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;lang&#39;</span><span class="p">:</span> <span class="n">lang</span><span class="p">,</span> <span class="s1">&#39;username&#39;</span><span class="p">:</span> <span class="n">username</span><span class="p">})</span><br/>    <span class="n">url</span> <span class="o">=</span> <span class="s1">&#39;http://api.geonames.org/countryInfoJSON?</span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">params</span><br/>    <span class="n">f</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">url</span><span class="p">)</span><br/>    <span class="n">response_text</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><br/>    <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response_text</span><span class="p">)[</span><span class="s2">&quot;geonames&quot;</span><span class="p">]</span><br/><br/><span class="k">def</span> <span class="nf">country_list_generator</span><span class="p">(</span><span class="n">country_list</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span><br/>    <span class="sd">&quot;&quot;&quot;Returns a generator of countries.</span><br/><span class="sd">    They are sorted alphabetically,</span><br/><span class="sd">    and the func passed as argument is applied to each of them.&quot;&quot;&quot;</span><br/>    <span class="n">ordered</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">country_list</span><span class="p">,</span><br/>        <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">k</span><span class="p">:</span> <span class="n">strip_accents</span><span class="p">(</span><span class="n">k</span><span class="p">[</span><span class="s1">&#39;countryName&#39;</span><span class="p">]))</span><br/>    <span class="k">return</span> <span class="p">(</span><span class="n">func</span><span class="p">(</span><span class="n">country</span><span class="p">)</span> <span class="k">for</span> <span class="n">country</span> <span class="ow">in</span> <span class="n">ordered</span><span class="p">)</span><br/><br/><span class="k">def</span> <span class="nf">country_to_option</span><span class="p">(</span><span class="n">country</span><span class="p">):</span><br/>    <span class="sd">&quot;&quot;&quot;Transforms a country dict to an html option tag,</span><br/><span class="sd">    The country code is used for the value.&quot;&quot;&quot;</span><br/>    <span class="k">return</span> <span class="p">(</span><span class="s1">&#39;&lt;option value=&quot;</span><span class="si">%s</span><span class="s1">&quot;&gt;</span><span class="si">%s</span><span class="s1">&lt;/option&gt;</span><span class="se">\n</span><span class="s1">&#39;</span> <span class="o">%</span> \<br/>        <span class="p">(</span><span class="n">country</span><span class="p">[</span><span class="s1">&#39;countryCode&#39;</span><span class="p">],</span> <span class="n">country</span><span class="p">[</span><span class="s1">&#39;countryName&#39;</span><span class="p">]))</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span><br/><br/><span class="k">def</span> <span class="nf">country_to_csharp_dict_pair</span><span class="p">(</span><span class="n">country</span><span class="p">):</span><br/>    <span class="sd">&quot;&quot;&quot;Transforms a country dict to a C# Dictionary pair.&quot;&quot;&quot;</span><br/>    <span class="k">return</span> <span class="p">(</span><span class="s1">&#39;{&quot;</span><span class="si">%s</span><span class="s1">&quot;, &quot;</span><span class="si">%s</span><span class="s1">&quot;},</span><span class="se">\n</span><span class="s1">&#39;</span> <span class="o">%</span> \<br/>        <span class="p">(</span><span class="n">country</span><span class="p">[</span><span class="s1">&#39;countryCode&#39;</span><span class="p">],</span> <span class="n">country</span><span class="p">[</span><span class="s1">&#39;countryName&#39;</span><span class="p">]))</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span><br/><br/><span class="k">def</span> <span class="nf">strip_accents</span><span class="p">(</span><span class="n">s</span><span class="p">):</span><br/>    <span class="sd">&quot;&quot;&quot;Removes the accents from a unicode string.</span><br/><span class="sd">    This function is used for sorting.&quot;&quot;&quot;</span><br/>    <span class="k">return</span> <span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">((</span><span class="n">c</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">unicodedata</span><span class="o">.</span><span class="n">normalize</span><span class="p">(</span><span class="s1">&#39;NFD&#39;</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span> \<br/>                        <span class="k">if</span> <span class="n">unicodedata</span><span class="o">.</span><span class="n">category</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="o">!=</span> <span class="s1">&#39;Mn&#39;</span><span class="p">))</span><br/><br/><span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span><br/>    <span class="n">country_list</span> <span class="o">=</span> <span class="n">get_list</span><span class="p">(</span><span class="s1">&#39;demo&#39;</span><span class="p">,</span> <span class="n">lang</span><span class="o">=</span><span class="s1">&#39;en&#39;</span><span class="p">)</span><br/>    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">&#39;output.txt&#39;</span><span class="p">,</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span><br/>        <span class="n">gen</span> <span class="o">=</span> <span class="n">country_list_generator</span><span class="p">(</span><span class="n">country_list</span><span class="p">,</span> <span class="n">country_to_option</span><span class="p">)</span><br/>        <span class="n">f</span><span class="o">.</span><span class="n">writelines</span><span class="p">(</span><span class="n">gen</span><span class="p">)</span><br/></pre></div>

<p>Hope it's useful to someone else.</p>
<p>The code is on <a href="https://github.com/antoineleclair/country-list-with-country-code">Github</a>.</p>]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://antoineleclair.ca</uri>
    </author>
    <title type="html"><![CDATA[Styling Google Maps]]></title>
    <link rel="alternate" type="text/html" href="http://antoineleclair.ca/2011/08/29/styling-google-maps/" />
    <id>http://antoineleclair.ca/2011/08/29/styling-google-maps/</id>
    <updated>2011-08-29T22:54:00Z</updated>
    <published>2011-08-29T22:54:00Z</published>
    <category scheme="http://antoineleclair.ca" term="Uncategorized" />
    <summary type="html"><![CDATA[Styling Google Maps]]></summary>
    <content type="html" xml:base="http://antoineleclair.ca/2011/08/29/styling-google-maps/"><![CDATA[<p>It seems to be a little known fact that you can add custom styles to Google
Maps using the Javascript API.</p>
<p>It's really not that complex and we use it often for client sites.</p>
<div id="styled-maps-example-1"></div>

<p>First thing to do is create the JSON to use for the style. You can use
<a href="http://gmaps-samples-v3.googlecode.com/svn/trunk/styledmaps/wizard/index.html">this wizard</a>,
it's a great tool for that.</p>
<p>Then you use the JSON in your Javascript like so:</p>
<div class="pygments_default"><pre><span></span><span class="c1">// your JSON</span><br/><span class="kd">var</span> <span class="nx">mapStyle</span> <span class="o">=</span> <span class="p">[</span><br/>  <span class="p">{</span><br/>      <span class="nx">featureType</span><span class="o">:</span> <span class="s2">&quot;landscape&quot;</span><span class="p">,</span><br/>      <span class="nx">elementType</span><span class="o">:</span> <span class="s2">&quot;all&quot;</span><span class="p">,</span><br/>      <span class="nx">stylers</span><span class="o">:</span> <span class="p">[</span><br/>      <span class="p">{</span> <span class="nx">hue</span><span class="o">:</span> <span class="s2">&quot;#ff4d00&quot;</span> <span class="p">},</span><br/>      <span class="p">{</span> <span class="nx">lightness</span><span class="o">:</span> <span class="o">-</span><span class="mi">72</span> <span class="p">},</span><br/>      <span class="p">{</span> <span class="nx">saturation</span><span class="o">:</span> <span class="o">-</span><span class="mi">74</span> <span class="p">}</span><br/>    <span class="p">]</span><br/>  <span class="p">}</span><br/><span class="p">];</span><br/><br/><span class="c1">// usual Google Maps code, plus styling</span><br/><span class="kd">var</span> <span class="nx">map</span><span class="p">;</span><br/><br/><span class="nx">$</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span><br/>    <span class="kd">var</span> <span class="nx">mapOptions</span> <span class="o">=</span> <span class="p">{</span><br/>        <span class="nx">zoom</span><span class="o">:</span> <span class="mi">12</span><span class="p">,</span><br/>        <span class="nx">mapTypeId</span><span class="o">:</span> <span class="s1">&#39;MapStyle&#39;</span><span class="p">,</span><br/>        <span class="nx">mapTypeControlOptions</span><span class="o">:</span> <span class="p">{</span><br/>            <span class="nx">mapTypeIds</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;MapStyle&#39;</span><span class="p">,</span> <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">MapTypeId</span><span class="p">.</span><span class="nx">SATELLITE</span><span class="p">]</span><br/>        <span class="p">}</span><br/>    <span class="p">};</span><br/><br/>    <span class="kd">var</span> <span class="nx">styledMapOptions</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">&quot;Map&quot;</span> <span class="p">};</span><br/><br/>    <span class="nx">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">Map</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&quot;styled-maps-example-1&quot;</span><span class="p">),</span> <span class="nx">mapOptions</span><span class="p">);</span><br/>    <span class="nx">map</span><span class="p">.</span><span class="nx">setCenter</span><span class="p">(</span><span class="k">new</span> <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">LatLng</span><span class="p">(</span><span class="mf">46.8</span><span class="p">,</span><span class="o">-</span><span class="mf">71.25</span><span class="p">));</span><br/>    <span class="kd">var</span> <span class="nx">mapType</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">StyledMapType</span><span class="p">(</span><span class="nx">mapStyle</span><span class="p">,</span> <span class="nx">styledMapOptions</span><span class="p">);</span><br/>    <span class="nx">map</span><span class="p">.</span><span class="nx">mapTypes</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;MapStyle&#39;</span><span class="p">,</span> <span class="nx">mapType</span><span class="p">);</span><br/>    <span class="nx">map</span><span class="p">.</span><span class="nx">setMapTypeId</span><span class="p">(</span><span class="s1">&#39;MapStyle&#39;</span><span class="p">);</span><br/><span class="p">});</span><br/></pre></div>

<p>It's even in the <a href="https://developers.google.com/maps/documentation/javascript/styling">docs</a>.
I don't see any reason why there's so little use of this feature.</p>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>

<script type="text/javascript">
var mapStyle = [
  {
      featureType: "landscape",
      elementType: "all",
      stylers: [
      { hue: "#ff4d00" },
      { lightness: -72 },
      { saturation: -74 }
    ]
  }, {
      featureType: "water",
      elementType: "all",
      stylers: [
      { hue: "#ff3c00" },
      { saturation: -67 },
      { lightness: -80 }
    ]
  }, {
      featureType: "administrative",
      elementType: "all",
      stylers: [
      { invert_lightness: true },
      { gamma: 2.51 },
      { lightness: 23 },
      { saturation: 6 }
    ]
  }, {
      featureType: "poi",
      elementType: "all",
      stylers: [
      { visibility: "off" }
    ]
  }, {
      featureType: "road.highway",
      elementType: "all",
      stylers: [
      { hue: "#ff4400" },
      { saturation: -90 }
    ]
  }, {
      featureType: "transit",
      elementType: "all",
      stylers: [
      { visibility: "off" },
      { saturation: -81 }
    ]
  }, {
      featureType: "road.arterial",
      elementType: "all",
      stylers: [
      { lightness: -32 },
      { hue: "#ff4400" },
      { saturation: -93 },
      { invert_lightness: true },
      { gamma: 0.73 }
    ]
  }, {
      featureType: "road.local",
      elementType: "all",
      stylers: [
      { saturation: -70 },
      { invert_lightness: true },
      { lightness: -17 },
      { gamma: 0.56 }
    ]
  }
];

var map;

$(function () {
    $('#styled-maps-example-1').css('height', '400px');

    var mapOptions = {
        zoom: 12,
        mapTypeId: 'MapStyle',
        mapTypeControlOptions: {
            mapTypeIds: ['MapStyle', google.maps.MapTypeId.SATELLITE]
        }
    };

    var styledMapOptions = { name: "Map" };

    map = new google.maps.Map(document.getElementById("styled-maps-example-1"), mapOptions);
    map.setCenter(new google.maps.LatLng(46.8,-71.25));
    var mapType = new google.maps.StyledMapType(mapStyle, styledMapOptions);
    map.mapTypes.set('MapStyle', mapType);
    map.setMapTypeId('MapStyle');
});
</script>]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://antoineleclair.ca</uri>
    </author>
    <title type="html"><![CDATA[Understanding Quadratic Bézier Curves]]></title>
    <link rel="alternate" type="text/html" href="http://antoineleclair.ca/2011/08/27/understanding-quadratic-bezier-curves/" />
    <id>http://antoineleclair.ca/2011/08/27/understanding-quadratic-bezier-curves/</id>
    <updated>2011-08-27T11:30:00Z</updated>
    <published>2011-08-27T11:30:00Z</published>
    <category scheme="http://antoineleclair.ca" term="Uncategorized" />
    <summary type="html"><![CDATA[Understanding Quadratic Bézier Curves]]></summary>
    <content type="html" xml:base="http://antoineleclair.ca/2011/08/27/understanding-quadratic-bezier-curves/"><![CDATA[<p>In a client project I had to draw by hand a quadratic Bézier curve, because the
html5 canvas quadraticCurveTo does not return the information about the path
drawn and I needed it.</p>
<p>Some basic explanation of a quadratic Bézier curve. You have a
start point <code>P1</code>, an end point <code>P2</code> and a control point <code>C</code>. Both the <code>x</code> and
<code>y</code> of each point on the path is dependant on <code>t</code>, which will vary from
0 to 1. <code>t=0</code> at the begining of the curve and <code>t=1</code> and the end of the curve.</p>
<p>You draw an imaginary line between <code>P1</code> and <code>C</code> (<code>P1C</code> line) and
another one between <code>C</code> and <code>P2</code> (<code>CP2</code> line). For each value of <code>t</code>, you mark
an imaginary point on <code>P1C</code> and <code>CP2</code>. The point on <code>P1C</code> is at <code>t</code> of the line,
starting at <code>P1</code>, and the point on the <code>CP2</code> line is at <code>t</code> of the line,
starting at <code>C</code>. Let's call those points <code>C1</code> and <code>C2</code>.</p>
<p>Then, you draw an imaginary line between <code>C1</code> and <code>C2</code>, and you mark a real
point at <code>t</code> of the <code>C1C2</code> line.</p>
<p>You repeat the procedure for every value of <code>t</code>, where <code>t</code> varies from 0 to 1.
All the points you marked on the line <code>C1C2</code> are showing the quadratic Bézier
curve.</p>
<p>Here's a little animation I made to explain it better:</p>
<div id="bezier-example-1" style="position:relative;">
    <canvas class="curve" style="position:absolute;top:0;left:0;z-index:4;"></canvas>
    <canvas class="animation" style="position:absolute;top:0;left:0;z-index:3;"></canvas>
    <canvas class="points" style="position:absolute;top:0;left:0;z-index:2;"></canvas>
    <canvas class="grid" style="position:absolute;top:0;left:0;z-index:1;"></canvas>
</div>

<p id="bezier-example-1-t">t = <span>0</span></p>

<script type="text/javascript">
    $(function() {

        var CANVAS_WIDTH = 301;
        var CANVAS_HEIGHT = 301;
        var p1x = 20;
        var p1y = 200;
        var cx = 140;
        var cy = 20;
        var p2x = 280;
        var p2y = 280;
        if (Modernizr.canvas) {
            var $t = $('#bezier-example-1-t span');
            $('#bezier-example-1').css({
                width: CANVAS_WIDTH + 'px',
                height: CANVAS_HEIGHT + 'px'
            });
            var gridCanvas = $('#bezier-example-1 .grid').get(0);
            var gridContext = gridCanvas.getContext('2d');
            gridCanvas.width = CANVAS_WIDTH;
            gridCanvas.height = CANVAS_HEIGHT;

            var pointsCanvas = $('#bezier-example-1 .points').get(0);
            var pointsContext = pointsCanvas.getContext('2d');
            pointsCanvas.width = CANVAS_WIDTH;
            pointsCanvas.height = CANVAS_HEIGHT;

            var animationCanvas = $('#bezier-example-1 .animation').get(0);
            var animationContext = animationCanvas.getContext('2d');
            animationCanvas.width = CANVAS_WIDTH;
            animationCanvas.height = CANVAS_HEIGHT;

            var curveCanvas = $('#bezier-example-1 .curve').get(0);
            var curveContext = curveCanvas.getContext('2d');
            curveCanvas.width = CANVAS_WIDTH;
            curveCanvas.height = CANVAS_HEIGHT;
            curveContext.strokeStyle = "#777";
            curveContext.lineWidth = 2;
            curveContext.beginPath();
            curveContext.moveTo(p1x, p1y);
            curveContext.stroke();

            drawGrid();
            drawSetup();
            setInterval(updateDemo, 1000/30);
        } else {
            $('#bezier-example-1').html('Your browser does not support Canvas.');
            $('#bezier-example-1-t').remove();
        }
        var t = 0;
        var d = 1; // direction

        function updateDemo() {
            if (t > 1 || t < 0) {
                d *= -1; // change direction
                curveContext.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
                curveContext.beginPath();
            }
            t += 0.01 * d; // continue moving
            $t.html(Math.round(t*100)/100);
            // update values
            var c1x = p1x + (cx - p1x) * t;
            var c1y = p1y + (cy - p1y) * t;
            var c2x = cx + (p2x - cx) * t;
            var c2y = cy + (p2y - cy) * t;
            var tx = c1x + (c2x - c1x) * t;
            var ty = c1y + (c2y - c1y) * t;

            animationContext.save();
            // clear old sketch
            animationContext.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
            // draw new line
            animationContext.beginPath();
            animationContext.strokeStyle = '#aaa';
            animationContext.lineWidth = 1;
            animationContext.moveTo(c1x, c1y);
            animationContext.lineTo(c2x, c2y);
            animationContext.stroke();
            // draw points on lines
            drawPoint(animationContext, c1x, c1y, 2, '#0f0');
            drawPoint(animationContext, c2x, c2y, 2, '#0f0');
            // draw point on curve
            drawPoint(animationContext, tx, ty, 3, '#f0f');
            animationContext.restore();

            // draw the Bézier curve by hand
            curveContext.lineTo(tx, ty);
            curveContext.stroke();         
        }            

        function drawSetup() {

            pointsContext.save();
            // lines between p1, c and p2
            pointsContext.strokeStyle = "#ddd";
            pointsContext.lineWidth = 2;
            pointsContext.beginPath();
            pointsContext.moveTo(p1x, p1y);
            pointsContext.lineTo(cx, cy);
            pointsContext.lineTo(p2x, p2y);
            pointsContext.stroke();
            pointsContext.closePath();
            // quadratic Bézier curve
            pointsContext.beginPath();
            pointsContext.strokeStyle = '#999';
            pointsContext.lineWidth = 1;
            pointsContext.moveTo(p1x, p1y);
            pointsContext.quadraticCurveTo(cx,cy, p2x, p2y);
            pointsContext.stroke();                
            pointsContext.restore();

            // circles marking p1, c and p2
            drawPoint(pointsContext, p1x, p1y, 5, '#00f');
            drawPoint(pointsContext, cx, cy, 5, '#f00');
            drawPoint(pointsContext, p2x, p2y, 5, '#00f');
            pointsContext.fillText("P1", p1x+10, p1y+10);                
            pointsContext.fillText("C", cx+10,  cy-5);                
            pointsContext.fillText("P2", p2x-20, p2y+10);                
        }

        function drawPoint(ctx, x, y, radius, color) {
            ctx.save();
            ctx.fillStyle = color;
            ctx.beginPath();
            ctx.arc(x, y, radius, 2 * Math.PI, false);
            ctx.fill();
            ctx.closePath();
            ctx.restore();
        }

        function drawGrid() {
            gridContext.save();
            gridContext.strokeStyle = '#ddd';
            gridContext.lineWidth = 1;
            for (var i = 0; i < CANVAS_HEIGHT; i += 20) {
                gridContext.beginPath();
                gridContext.moveTo(0, i);
                gridContext.lineTo(CANVAS_WIDTH, i);
                gridContext.stroke();
            }
            for (var i = 0; i < CANVAS_WIDTH; i += 20) {
                gridContext.beginPath();
                gridContext.moveTo(i, 0);
                gridContext.lineTo(i, CANVAS_HEIGHT);
                gridContext.stroke();
                gridContext.closePath();
            }
            gridContext.restore();
        }
    });
</script>

<p>You can have a look at the source for a complete understanding, but here's the
important part, edited for clarity:</p>
<div class="pygments_default"><pre><span></span><span class="c1">// constants</span><br/><span class="kd">var</span> <span class="nx">CANVAS_WIDTH</span> <span class="o">=</span> <span class="mi">301</span><span class="p">;</span><br/><span class="kd">var</span> <span class="nx">CANVAS_HEIGHT</span> <span class="o">=</span> <span class="mi">301</span><span class="p">;</span><br/><span class="kd">var</span> <span class="nx">p1x</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span><br/><span class="kd">var</span> <span class="nx">p1y</span> <span class="o">=</span> <span class="mi">200</span><span class="p">;</span><br/><span class="kd">var</span> <span class="nx">cx</span> <span class="o">=</span> <span class="mi">140</span><span class="p">;</span><br/><span class="kd">var</span> <span class="nx">cy</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span><br/><span class="kd">var</span> <span class="nx">p2x</span> <span class="o">=</span> <span class="mi">280</span><span class="p">;</span><br/><span class="kd">var</span> <span class="nx">p2y</span> <span class="o">=</span> <span class="mi">280</span><span class="p">;</span><br/><br/><span class="c1">// basic setup</span><br/><span class="kd">var</span> <span class="nx">$t</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;#bezier-example-1-t span&#39;</span><span class="p">);</span><br/><br/><span class="kd">var</span> <span class="nx">animationCanvas</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;#bezier-example-1 .animation&#39;</span><span class="p">).</span><span class="nx">get</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><br/><span class="kd">var</span> <span class="nx">animationContext</span> <span class="o">=</span> <span class="nx">animationCanvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="s1">&#39;2d&#39;</span><span class="p">);</span><br/><span class="nx">animationCanvas</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">CANVAS_WIDTH</span><span class="p">;</span><br/><span class="nx">animationCanvas</span><span class="p">.</span><span class="nx">height</span> <span class="o">=</span> <span class="nx">CANVAS_HEIGHT</span><span class="p">;</span><br/><br/><span class="kd">var</span> <span class="nx">curveCanvas</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;#bezier-example-1 .curve&#39;</span><span class="p">).</span><span class="nx">get</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><br/><span class="kd">var</span> <span class="nx">curveContext</span> <span class="o">=</span> <span class="nx">curveCanvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="s1">&#39;2d&#39;</span><span class="p">);</span><br/><span class="nx">curveCanvas</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">CANVAS_WIDTH</span><span class="p">;</span><br/><span class="nx">curveCanvas</span><span class="p">.</span><span class="nx">height</span> <span class="o">=</span> <span class="nx">CANVAS_HEIGHT</span><span class="p">;</span><br/><span class="nx">curveContext</span><span class="p">.</span><span class="nx">strokeStyle</span> <span class="o">=</span> <span class="s2">&quot;#777&quot;</span><span class="p">;</span><br/><span class="nx">curveContext</span><span class="p">.</span><span class="nx">lineWidth</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span><br/><span class="nx">curveContext</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span><br/><span class="nx">curveContext</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="nx">p1x</span><span class="p">,</span> <span class="nx">p1y</span><span class="p">);</span><br/><span class="nx">curveContext</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span><br/><br/><span class="nx">setInterval</span><span class="p">(</span><span class="nx">updateDemo</span><span class="p">,</span> <span class="mi">1000</span><span class="o">/</span><span class="mi">30</span><span class="p">);</span><br/><br/><span class="kd">var</span> <span class="nx">t</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span><br/><span class="kd">var</span> <span class="nx">d</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// direction</span><br/><br/><span class="kd">function</span> <span class="nx">updateDemo</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// called 30 times/second to animate</span><br/>    <span class="k">if</span> <span class="p">(</span><span class="nx">t</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="o">||</span> <span class="nx">t</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span><br/>        <span class="nx">d</span> <span class="o">*=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="c1">// change direction</span><br/>        <span class="nx">curveContext</span><span class="p">.</span><span class="nx">clearRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">CANVAS_WIDTH</span><span class="p">,</span> <span class="nx">CANVAS_HEIGHT</span><span class="p">);</span><br/>        <span class="nx">curveContext</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span><br/>    <span class="p">}</span><br/>    <span class="nx">t</span> <span class="o">+=</span> <span class="mf">0.01</span> <span class="o">*</span> <span class="nx">d</span><span class="p">;</span> <span class="c1">// continue moving</span><br/>    <span class="nx">$t</span><span class="p">.</span><span class="nx">html</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">round</span><span class="p">(</span><span class="nx">t</span><span class="o">*</span><span class="mi">100</span><span class="p">)</span><span class="o">/</span><span class="mi">100</span><span class="p">);</span><br/>    <span class="c1">// update values</span><br/>    <span class="kd">var</span> <span class="nx">c1x</span> <span class="o">=</span> <span class="nx">p1x</span> <span class="o">+</span> <span class="p">(</span><span class="nx">cx</span> <span class="o">-</span> <span class="nx">p1x</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span><br/>    <span class="kd">var</span> <span class="nx">c1y</span> <span class="o">=</span> <span class="nx">p1y</span> <span class="o">+</span> <span class="p">(</span><span class="nx">cy</span> <span class="o">-</span> <span class="nx">p1y</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span><br/>    <span class="kd">var</span> <span class="nx">c2x</span> <span class="o">=</span> <span class="nx">cx</span> <span class="o">+</span> <span class="p">(</span><span class="nx">p2x</span> <span class="o">-</span> <span class="nx">cx</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span><br/>    <span class="kd">var</span> <span class="nx">c2y</span> <span class="o">=</span> <span class="nx">cy</span> <span class="o">+</span> <span class="p">(</span><span class="nx">p2y</span> <span class="o">-</span> <span class="nx">cy</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span><br/>    <span class="kd">var</span> <span class="nx">tx</span> <span class="o">=</span> <span class="nx">c1x</span> <span class="o">+</span> <span class="p">(</span><span class="nx">c2x</span> <span class="o">-</span> <span class="nx">c1x</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span><br/>    <span class="kd">var</span> <span class="nx">ty</span> <span class="o">=</span> <span class="nx">c1y</span> <span class="o">+</span> <span class="p">(</span><span class="nx">c2y</span> <span class="o">-</span> <span class="nx">c1y</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span><br/>    <br/>    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">save</span><span class="p">();</span><br/>    <span class="c1">// clear old sketch</span><br/>    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">clearRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">CANVAS_WIDTH</span><span class="p">,</span> <span class="nx">CANVAS_HEIGHT</span><span class="p">);</span><br/>    <span class="c1">// draw new line</span><br/>    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span><br/>    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">strokeStyle</span> <span class="o">=</span> <span class="s1">&#39;#aaa&#39;</span><span class="p">;</span><br/>    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">lineWidth</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span><br/>    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="nx">c1x</span><span class="p">,</span> <span class="nx">c1y</span><span class="p">);</span><br/>    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="nx">c2x</span><span class="p">,</span> <span class="nx">c2y</span><span class="p">);</span><br/>    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span><br/>    <span class="c1">// draw points on lines</span><br/>    <span class="nx">drawPoint</span><span class="p">(</span><span class="nx">animationContext</span><span class="p">,</span> <span class="nx">c1x</span><span class="p">,</span> <span class="nx">c1y</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;#0f0&#39;</span><span class="p">);</span><br/>    <span class="nx">drawPoint</span><span class="p">(</span><span class="nx">animationContext</span><span class="p">,</span> <span class="nx">c2x</span><span class="p">,</span> <span class="nx">c2y</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;#0f0&#39;</span><span class="p">);</span><br/>    <span class="c1">// draw point on curve</span><br/>    <span class="nx">drawPoint</span><span class="p">(</span><span class="nx">animationContext</span><span class="p">,</span> <span class="nx">tx</span><span class="p">,</span> <span class="nx">ty</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s1">&#39;#f0f&#39;</span><span class="p">);</span><br/>    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">restore</span><span class="p">();</span><br/>    <br/>    <span class="c1">// draw the new Bezier curve segment</span><br/>    <span class="nx">curveContext</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="nx">tx</span><span class="p">,</span> <span class="nx">ty</span><span class="p">);</span><br/>    <span class="nx">curveContext</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span><br/><span class="p">}</span><br/></pre></div>

<p>The code is on
<a href="https://github.com/antoineleclair/Understanding-Bezier-Curve">Github</a>.</p>]]></content>
  </entry>
</feed>
