<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[jwinter.org]]></title>
  <link href="http://jwinter.org/blog/atom.xml" rel="self"/>
  <link href="http://jwinter.org/blog/"/>
  <updated>2014-11-12T10:31:50-05:00</updated>
  <id>http://jwinter.org/blog/</id>
  <author>
    <name><![CDATA[Joe W.]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Code Reviews @jwinter-style]]></title>
    <link href="http://jwinter.org/blog/2014/10/31/code-review-jwinter-style/"/>
    <updated>2014-10-31T00:00:00-04:00</updated>
    <id>http://jwinter.org/blog/2014/10/31/code-review-jwinter-style</id>
    <content type="html"><![CDATA[<p>I really enjoy reviewing code. I think it&#8217;s mostly because I enjoy listening and talking to people about programming. So here are some of my rambling thoughts on reviewing code.</p>

<p>First, I <strong>try to be cognizant of other people&#8217;s feelings during code review</strong>. It&#8217;s easy to be rude by giving curt, negative feedback. Sometimes it takes more time to reword a comment in more sensitive language. I&#8217;ve never regretted taking the time to do that. I have regretted hastily sending off a comment that sounds like a jerk wrote it.</p>

<p>Speaking of which, there have been times where following my feedback would have <strong>absolutely</strong> resulted in a change for the worse. If you review code long enough and have a modicum of self-awareness, this will also happen to you. Be prepared for it and let the author and other reviewers know when you change your mind.</p>

<p>I also try to respect the author of the pull request by doing the following (and sometimes I screw this up):</p>

<ol>
<li>Point out what they&#8217;ve done well! Everybody forgets this one! Why don&#8217;t you do this?!</li>
<li>Phrase refactoring suggestions as suggestions. Rarely, I &#8220;very strongly&#8221; suggest a refactoring, but even in that case I try to say so in a way that respects the work that&#8217;s already gone into this change.</li>
<li>Ask before I add commits to their pull request. If I don&#8217;t get a response quickly, I&#8217;ll generally just put some sample code into my comments to show what I&#8217;m suggesting.</li>
<li>Provide performance specifics. When I think the code is too slow, instead of just saying something like &#8220;This looks too slow&#8221;, I&#8217;ll try to provide specific numbers or offer help in profiling.</li>
<li>OFFER HELP! I&#8217;ll offer to pair on something during or after a review.</li>
<li>When I do think the code needs reworking, I either provide a specific way to improve the code or have one in mind. I won&#8217;t always offer the change I have in mind because that sometimes narrows the author&#8217;s thinking on how to make an improvement.</li>
</ol>


<p>So here are the actual steps I go through.</p>

<p>First, I <strong>check out the branch to review in my local git repo</strong>. If you don&#8217;t check out the branch you&#8217;re reviewing locally, I&#8217;m not really sure how you can provide a close review. There&#8217;s several important steps below that you just can&#8217;t do by looking at the code on Github alone.</p>

<p>Next, if the branch won&#8217;t merge cleanly, I&#8217;ll rebase it locally (and not push my changes) before starting this process. If there are a lot of merge conflicts, I&#8217;ll ask for the author to merge master into this branch or rebase it on master, or whatever they prefer to get it closer to our master branch.</p>

<p><strong>Then, I run our entire test suite (unit, functional, integration, whatever) locally.</strong> Some may be wondering why I just don&#8217;t just let our continuous integration server run the tests on the branch. I run tests locally, in addition to the CI server, because once this code passes review, it will be the new master branch. And I will be using that immediately in whatever I&#8217;m working on. So if my local dev environment is going to start failing tests, I want to know as soon as possible. It&#8217;s also a great time to ask for help because the person sending the pull request still has the code fresh in their mind and is especially motivated to get the change through.</p>

<p>While the tests are running, I read the diffs on Github. <strong>I like to look at the whole diff across all files.</strong> If it&#8217;s a particularly large or complicated pull request, I may drill into specific commits. But I don&#8217;t really care which commit a particular change came from, since I&#8217;m not reviewing that commit I&#8217;m reviewing the whole branch.</p>

<p><strong>Some quick things I look for on my first pass:</strong></p>

<ol>
<li>Any change where there&#8217;s not a corresponding change in test code</li>
<li>New methods or variables that go unused</li>
<li>Anything that doesn&#8217;t match our (implicit or explict) style guide</li>
<li>Anything that reminds me of a bug I&#8217;ve hit before. An example here might be using ||= for memoization in Ruby</li>
<li>Any goddamn trailing whitespace</li>
<li>Anything that I want to take a closer look at</li>
</ol>


<p>Things that fall under that last bullet would be any change in data structure, any new data structures, any change in logic or addition of new logic, etc. Basically anything other than the simplest 1-2 line change where only I could screw it up, I&#8217;ll want to take a closer look at.</p>

<p>After that first pass, I&#8217;ll either be just about done if it&#8217;s a small change or ready to start taking a closer look at the bits I&#8217;ve identified from the first pass.</p>

<p>This is the point where I usually <strong>read the request that spawned this change</strong> (bug report/feature request/bar napkin) and then <strong>actually use the new feature or attempt to repro the bug</strong>. I don&#8217;t think most people do this. This is a really important step, maybe the most important, so please actually run the code that you&#8217;re reviewing.</p>

<p><strong>Now, when taking a closer look, I&#8217;ll do any combination of the following:</strong></p>

<ol>
<li>Think about how the change will run in production.</li>
<li>Reverse their logic and make sure the right tests fail.</li>
<li>Drop into the debugger and walk through the code to see if it runs how I expect.</li>
<li>Copy their code into a REPL and make sure it does what I think it&#8217;s supposed to.</li>
<li>Walk back up call stack to see if any of the arguments expected to be one type are actually of that type, e.g. non-null, array, etc.</li>
<li>Write a (or run an existing) load or stress test.</li>
</ol>


<p>And <strong>before I finally +1 the change I check that:</strong></p>

<ol>
<li>Every comment I&#8217;ve made has been responded to, either with code or with a discussion.</li>
<li>All tests pass locally.</li>
<li>Any new ideas or features that have come out of review are tracked somewhere.</li>
<li>It still merges cleanly. I&#8217;ve seen enough bugs introduced during merge resolution that I&#8217;ll ask folks to merge master or rebase before completing my review.</li>
</ol>


<p>So what&#8217;s above is what I use to help me improve the code I look at. I&#8217;m very interested in what helps others do the same. <strong>Get at me at <a href="https://twitter.com/jwinter">@jwinter on twitter</a> if you&#8217;ve got feedback on this.</strong> I&#8217;d love to hear it.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Docker Resources]]></title>
    <link href="http://jwinter.org/blog/2013/08/19/docker-resources/"/>
    <updated>2013-08-19T00:00:00-04:00</updated>
    <id>http://jwinter.org/blog/2013/08/19/docker-resources</id>
    <content type="html"><![CDATA[More background on Docker:
http://www.docker.io/the-whole-story/

Their very cool Interactive Tutorial:
https://www.docker.io/gettingstarted/

Installation via vagrant:
http://docs.docker.io/en/latest/installation/vagrant/

dotCloud (creators of Docker) had a series of blog posts on building a PaaS that included ones on LXC and AUFS:
http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part
http://blog.dotcloud.com/kernel-secrets-from-the-paas-garage-part-34-a
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A Short Talk on Docker]]></title>
    <link href="http://jwinter.org/blog/2013/08/13/docker/"/>
    <updated>2013-08-13T00:00:00-04:00</updated>
    <id>http://jwinter.org/blog/2013/08/13/docker</id>
    <content type="html"><![CDATA[<p>I gave a short talk on <a href="http://docker.io">Docker</a>
at <a href="http://phillyrb.org">PhillyRB</a>&#8217;s August
meeting.  <a href="http://slideshare.net/jwatnj/docker">These were my slides</a>, although I went way off of them and only got through about
half. What follows are the notes I used for my talk.</p>

<h3>What&#8217;s Docker?</h3>

<h4>3 things I&#8217;d like you to take from this talk:</h4>
<ul>
<li> Docker provides a lot of the advantages of virtual machines without the disadvantages
<li> Container-based deployment is a great way to deploy applications
<li> AUFS and LXC are the chocolate and peanut butter that makes Docker so great to use
</ul>

<h4>What&#8217;s a container?</h4>
<p>It&#8217;s like a virtual machine. When your app is running inside a
container, it appears to be running inside its own OS. But there could
be many other containers running alongside yours, all sharing
resources. It uses a combination of LXC (Linux containers) and AUFS (A
union/layered/snapshotting filesystem). I&#8217;ll talk about both more
later</p>

<p>They&#8217;re also a means of packaging. You can build a container and
run it anywhere that can run docker. You can share that container with
other people and know that it will run the same way.</p>


<h4>Why are they useful?</h4>

<ul>
<li> Run your whole damn stack<br/>
Run your Rails app on your laptop by grabbing a container with RVM
installed, another container with PostgreSQL, another container with
Redis, another with ElasticSearch or Solr.  If you&#8217;ve ever tried to
run multi-node Vagrant, it&#8217;s really painful and slow to spin up
several nodes. Docker makes it very fast and easy.
</li>
<li> Reduce dependencies by shipping dependencies inside the container<br/>
Compile native gems or anything else once inside your container and
ship that everywhere instead of building on each server.
</li>
<li> Cut down on configuration errors in production<br/>
Configure your OS inside the container then snapshot.
</li>

<li> They&#8217;re fast <br/>
Much faster and less resource intensive than VMs.
As we&#8217;ll see in the demo, you can spin one up almost instantly.
</li>

<li> Deploy Once, Deploy Anywhere<br/>
Once you&#8217;ve built a container, and committed it as an image
you can run it anywhere
</li>

<li>Let someone else do the work for you<br/> 
The ability to package and share containers means that you can use
someone else&#8217;s work to start from a known functional state. It&#8217;s like
sharing chef cookbooks.
</li>

<li>Easy to build<br/>
Make a mistake building your application, no problem,
every successful step is automatically snapshotted.
If you&#8217;ve ever tried provisioning VMs with vagrant you know you&#8217;re
almost always starting over every time.
</li>
</ul>

<h4>What does working with containers look like?</h4>
<p>Demo goes here.</p>

<h4>How do containers work?</h4>
<h4>LXC</h4>
<ul>
<li>LXC gives you isolation and control over sharing of resources
<li>LXC namespaces are what makes each container appear to have its own networking,
process table, filesystem mount points, and hostname
<li>LXC is also how you say: &#8220;Give my Rails container 4GB of RAM, but my
database container 28GB&#8221;. It gives you some control over resource management including
IO ops/second and bytes per second.
</ul>

<h4>AUFS</h4>

<ul>
<li>AUFS, union or &#8220;layering&#8221; filesystem
<li>The filesystem layers give each container its own view of the complete
filesystem
<li>Base layer is the OS and is read-only
<li>Your container is read-write on top
<li>When you go to do a read, it hits your container first, then reads
through to the base if you haven&#8217;t made any changes
<li>Unchanged files are shared</li>
<li>Buffercache is also shared, so a certain portion of what&#8217;s shared on
disk is shared in memory as well.</li>
<li>This aspect is importants because it improves performance. Storage is
cheap, so who really cares that AUFS saves a few gigabytes, but the
fact that many dynamic libraries are shared across
containers in memory means that containers spin up very quickly.</li>
</ul>

<h4>Where can I find useful prebuilt containers?</h4>
<ul>
<li>https://index.docker.io/</li>
<li>Search Github for Dockerfiles</li>
</ul>

<h4>How do I build containers?</h4>
<ul>
<li>Dockerfile, like a Gemfile but more like a shell script</li>
<li>You list what image you want to start from, then you list
the commands you want to run, files you want to include, ports you
want to expose</li>
</ul>

<h4>What are the downsides?</h4>
<ul>
<li>It&#8217;s very new, but doesn&#8217;t feel buggy. There&#8217;s just not a lot of good answers yet for common
ops questions like what happens a container crashes or the daemon crashes or how to monitor?</li>
<li>Have to run your own repository to share private docker images</li>
</ul>


<h4>What&#8217;s the future?</h4>
<ul>
<li>Already several platforms like Heroku are popping up to support running Docker containers</li>
<li>Docker 1.0 in the fall</li>
<li>Like 100 committers on it and they just opensourced it</li>
<li>Docker is already changing how people ship software</li>
<li>Do MUCH less configuration in Chef, ship almost entirely configured containers</li>
<li>Test Chef recipes very quickly with test-kitchen-docker</li>
<li>Continuous Integration, test app inside lightweight container, ship
that container</li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Advice for Personal Projects]]></title>
    <link href="http://jwinter.org/blog/2013/01/18/advice-for-personal-projects/"/>
    <updated>2013-01-18T00:00:00-05:00</updated>
    <id>http://jwinter.org/blog/2013/01/18/advice-for-personal-projects</id>
    <content type="html"><![CDATA[<p><a href="http://movieos.org/blog/2013/rules-for-personal-projects/">http://movieos.org/blog/2013/rules-for-personal-projects/</a></p><p>This makes a lot of sense, I&#8217;m often lost when I try to go back to a personal project that I&#8217;ve left off for a few weeks. Something like a &#8220;run&#8221; bash script that just did &#8220;rails s &amp;&amp; open &#8216;http://localhost:3000/last_thing_i_worked_on&#8217;&#8221; would be good to get started again quickly. And taking the time to deploy the little Clojure projects I&#8217;ve done to heroku would be worthwhile.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Stubbing HTTP APIs with VCR]]></title>
    <link href="http://jwinter.org/blog/2012/10/16/stubbing-http-apis-with-vcr/"/>
    <updated>2012-10-16T00:00:00-04:00</updated>
    <id>http://jwinter.org/blog/2012/10/16/stubbing-http-apis-with-vcr</id>
    <content type="html"><![CDATA[]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Setting up a new MacBook Pro for Ruby / RoR development]]></title>
    <link href="http://jwinter.org/blog/2012/05/27/setting-up-a-new-macbook-pro-for-ruby-ror-dev/"/>
    <updated>2012-05-27T00:00:00-04:00</updated>
    <id>http://jwinter.org/blog/2012/05/27/setting-up-a-new-macbook-pro-for-ruby-ror-dev</id>
    <content type="html"><![CDATA[<p>Install Xcode _or_ just the Xcode command line utitilies (I installed all of Xcode)</p><p>&nbsp;</p><p>Pivotal Labs: soloist gem, pivotal_workstation</p><p>errored out on SizeUp</p><p>errored out on MacVim</p><p>errored out on gem_no_ri_no_rdoc</p><p>&nbsp;</p><p>Mouse Locator defaults to on and captures Ctrl-space. If you&#8217;re an emacs user, you&#8217;ll know why this is a problem.</p><p>&nbsp;</p><p>Installing ruby-1.8.7 `env CC=/usr/bin/gcc rvm install ruby-1.8.7`</p><p>&nbsp;</p><p>Things I installed manually, but would like to automate:</p><p>iTerm2 preference for swapping Cmd and Option AND making &#8220;Option&#8221; send Esc-+ (meta)</p><p>emacs 24 - look at the emacs24 recipe</p><p>Installed emacs from emacs 24 dmg</p><p>oh-my-zsh</p><p>&nbsp;</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA["Polyfills" for backwards compatibility]]></title>
    <link href="http://jwinter.org/blog/2010/10/12/polyfills-for-backwards-compatibility/"/>
    <updated>2010-10-12T00:00:00-04:00</updated>
    <id>http://jwinter.org/blog/2010/10/12/polyfills-for-backwards-compatibility</id>
    <content type="html"><![CDATA[<p>Modernizr has an awesome <a href="http://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills">list of HTML 5 &#8220;Polyfills&#8221;</a> (fallbacks to provide new features in older browsers with the same new API):</p><p>&nbsp;</p><p>&nbsp;</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[EventMachine timers]]></title>
    <link href="http://jwinter.org/blog/2010/09/24/eventmachine-timers/"/>
    <updated>2010-09-24T00:00:00-04:00</updated>
    <id>http://jwinter.org/blog/2010/09/24/eventmachine-timers</id>
    <content type="html"><![CDATA[<p>There is a limit on the number of running eventmachine timers you can use at one time. &nbsp;And cancelling a timer does *not* free up one of those slots for running timers, you must wait until the time when the timer would actually fire to free up a slot. The default on most systems is 1000 timers. set_max_timers(count) allows you to increase it.</p><p>This doesn&#8217;t apply to the pure Ruby eventmachine, it has no max_timer limit.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Emacs, ansi-term, and screen]]></title>
    <link href="http://jwinter.org/blog/2010/05/23/emacs-ansi-term-and-screen/"/>
    <updated>2010-05-23T00:00:00-04:00</updated>
    <id>http://jwinter.org/blog/2010/05/23/emacs-ansi-term-and-screen</id>
    <content type="html"><![CDATA[<p>C-c C-j turns your ansi-term buffer into a normal emacs buffer where you can copy/paste. C-c C-k switches it back.</p><p>So, for example, if you want to paste text into your ansi-term session, you&#8217;d copy that text from your emacs buffer, switch to your ansi-term buffer, hit C-c C-j, then M-y, then C-c C-k.</p><p>If you use emacs and you&#8217;re not using ansi-term and screen, you should give it a shot.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[James Brown Loves You]]></title>
    <link href="http://jwinter.org/blog/2009/12/24/james-brown-loves-you/"/>
    <updated>2009-12-24T00:00:00-05:00</updated>
    <id>http://jwinter.org/blog/2009/12/24/james-brown-loves-you</id>
    <content type="html"><![CDATA[<p><span style="font-size: 10px;"><object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/WcQJj7d18eA&hl=en_US&fs=1&rel=0" /></param><param name="allowFullScreen" value="true" /></param><param name="allowscriptaccess" value="always" /></param><embed allowfullscreen="true" src="http://www.youtube.com/v/WcQJj7d18eA&hl=en_US&fs=1&rel=0" allowscriptaccess="always" type="application/x-shockwave-flash" height="344" width="425"></embed></object></span></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Dough Was for Me!]]></title>
    <link href="http://jwinter.org/blog/2009/12/20/the-dough-was-for-me/"/>
    <updated>2009-12-20T00:00:00-05:00</updated>
    <id>http://jwinter.org/blog/2009/12/20/the-dough-was-for-me</id>
    <content type="html"><![CDATA[<p><span style="font-size: 10px;"><object height="303" width="500"><param name="movie" value="http://www.youtube.com/v/F_J4SBUwe5U&hl=en_US&fs=1&rel=0" /></param><param name="allowFullScreen" value="true" /></param><param name="allowscriptaccess" value="always" /></param><embed allowfullscreen="true" src="http://www.youtube.com/v/F_J4SBUwe5U&hl=en_US&fs=1&rel=0" allowscriptaccess="always" type="application/x-shockwave-flash" height="303" width="500"></embed></object></span></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[I Miss anywhere.fm]]></title>
    <link href="http://jwinter.org/blog/2009/12/18/i-miss-anywherefm/"/>
    <updated>2009-12-18T00:00:00-05:00</updated>
    <id>http://jwinter.org/blog/2009/12/18/i-miss-anywherefm</id>
    <content type="html"><![CDATA[<p>anywhere.fm was my favorite web application.&nbsp; If you weren&#8217;t lucky enough to use it while it was around, it was like a Web-based iTunes.&nbsp; You could upload all of your music to it and then play it from anywhere you had an internet connection and a Flash player.&nbsp;</p><p>The UI bore a strong resemblance to iTunes, but its best UI feature was that everything was fast.&nbsp; Searching for a song in your collection was fast, switching to a new playlist was fast, creating a new playlist was fast.&nbsp; There are very few (maybe GMail?) Web apps where I could do what I wanted to as quickly.</p><p>Their import process had two features that I haven&#8217;t seen anywhere else: a) a convenient desktop app to upload your music in the background and b) the ability to upload <strong>all</strong> of your music.&nbsp; The OS X native app to upload your music worked perfectly for me.&nbsp; It took a few days to get it all, but eventually I had several thousand songs uploaded to anywhere.fm.&nbsp;</p><p>I want to emphasize how happy it made me to have all of my music anywhere I was in front of a computer.</p><p>The anywhere story had a happy ending for the founders, but a sad one for their users.&nbsp; They were bought by imeem, which had an abysmal, sluggish interface and never migrated all of my music.&nbsp; Imeem was then acquired my MySpace Music which claims to have plans to migrate the music from Imeem.&nbsp; But there&#8217;s no chance MySpace will produce anything like anywhere.</p><p>I&#8217;m interested to see what the anywhere founders will build next, but they and YCombinator, the incubator that helped them get started, have lost a bit of my trust.&nbsp; I appreciate their hard work in building anywhere.&nbsp; But I&#8217;d like them to understand what it felt like when anywhere was taken away.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Odds Against Christmas Being Christmas Are Approximately 365 to 1.]]></title>
    <link href="http://jwinter.org/blog/2009/12/12/the-odds-against-christmas-being-christmas-ar/"/>
    <updated>2009-12-12T00:00:00-05:00</updated>
    <id>http://jwinter.org/blog/2009/12/12/the-odds-against-christmas-being-christmas-ar</id>
    <content type="html"><![CDATA[<p><span style="font-size: 10px;"><object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/IvfunCK3S_o&hl=en_US&fs=1&rel=0" /></param><param name="allowFullScreen" value="true" /></param><param name="allowscriptaccess" value="always" /></param><embed allowfullscreen="true" src="http://www.youtube.com/v/IvfunCK3S_o&hl=en_US&fs=1&rel=0" allowscriptaccess="always" type="application/x-shockwave-flash" height="344" width="425"></embed></object></span></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[JOGL and Clojure]]></title>
    <link href="http://jwinter.org/blog/2009/04/21/jogl-and-clojure/"/>
    <updated>2009-04-21T00:00:00-04:00</updated>
    <id>http://jwinter.org/blog/2009/04/21/jogl-and-clojure</id>
    <content type="html"><![CDATA[<p>JOGL is an OpenGL implementation in Java. Clojure is a Lisp that runs <br />on the JVM. <br />&nbsp;<br />Install JOGL <br />&nbsp;<br />Install Clojure <br />&nbsp;<br />Shortest code to draw a triangle on the screen. Use this to test that <br />everything was installed correctly. <br />&nbsp;<br /><code>(ns bb <br />&nbsp;(:import (java.awt Frame BorderLayout) <br />&nbsp;     (javax.swing JFrame) <br />&nbsp;     (java.awt.event WindowAdapter WindowEvent) <br />&nbsp;     (javax.media.opengl GL GLAutoDrawable GLDrawableFactory <br />&nbsp;               GLCanvas GLEventListener GLCapabilities) <br />&nbsp;     (com.sun.opengl.util Animator) <br />)) <br />&nbsp;;;Add a .dispose to this frame's windowClosing event <br />(defn window-closer [frame] <br />&nbsp;(proxy [WindowAdapter] [] <br />&nbsp; (windowClosing [event] <br />&nbsp;         (.start (new Thread <br />&nbsp;               (fn [] <br />&nbsp;                (.dispose frame))))))) <br />&nbsp;(defn gl-listener [] <br />&nbsp;(proxy [GLEventListener] [] <br />&nbsp; (init [drawable] <br />&nbsp;    (doto (.getGL drawable) <br />&nbsp;     (.glClearColor 0.0 0.0 0.0 1.0) <br />&nbsp;     (.glColor3f 0.0 0.0 0.0) <br />&nbsp;    )) <br />&nbsp; (display [drawable] <br />&nbsp;    (doto (.getGL drawable) <br />&nbsp;     (.glClear GL/GL_COLOR_BUFFER_BIT) <br />&nbsp;     (.glColor3f 1, 0, 0) <br />&nbsp;     (.glRecti 0 0 1 1) <br />&nbsp;     (.glColor3f 0.0 0.0 0.0) <br />&nbsp;     (.glMatrixMode GL/GL_MODELVIEW) <br />&nbsp;     (.glLoadIdentity) <br />&nbsp;     )) <br />&nbsp; (displayChanged [drawable mode device]) <br />&nbsp; (reshape [drawable x y w h]) <br />&nbsp; )) <br />&nbsp;;; Draw the scene <br />(defn main [] <br />&nbsp;(let [frame (new Frame "Hey dere Joe") <br />&nbsp;   gl-canvas (new GLCanvas) <br />&nbsp;   ] <br />&nbsp; (.addGLEventListener gl-canvas (gl-listener)) <br />&nbsp; (.setSize frame 600 600) <br />&nbsp; (.add frame gl-canvas) <br />&nbsp; (.setVisible frame true) <br />&nbsp; (.addWindowListener frame (window-closer frame))))</code></p>
]]></content>
  </entry>
  
</feed>
