<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-32811356</id><updated>2011-10-03T04:17:17.025-07:00</updated><title type='text'>Programming</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-32811356.post-8037018952681247314</id><published>2011-03-16T19:18:00.000-07:00</published><updated>2011-03-16T19:18:46.835-07:00</updated><title type='text'>Performance testing persistent maps</title><content type='html'>Persistent maps have the excellent property that they share structure, which enables them to produce copies efficiently.  I recently implemented a very simple RecordedMap which keeps a history of all changes that occur so that you can rewind time.  Naturally I wanted to know what the overhead I would pay for this feature was, so put together some tests to see:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Map Implementation&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;Time taken&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RecordedMapModel&lt;/td&gt;&lt;td&gt;00:00:00.9722224&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ClojureRecordedMapModel&lt;/td&gt;&lt;td&gt;00:00:04.9654442&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Dictionary&lt;/td&gt;&lt;td&gt;00:00:00.1727407&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Copy Dictionary&lt;/td&gt;&lt;td&gt;00:00:17.3513137&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FSharpMap&lt;/td&gt;&lt;td&gt;00:00:00.7329950&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PersistentTreeMap&lt;/td&gt;&lt;td&gt;00:00:04.4958646&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;Comparing a mutable dictionary directly to an immutable persistent FSharpMap we can see a performance cost of about 5x time, which is a little painful.  More than I was hoping for, but well within an order of magnitude.  So there is definitely a trade-off here.&lt;br /&gt;&lt;br /&gt;Keeping a full history of all previous versions of the map adds very little overhead, less than 50% (RecordedMapModel).  Using a copy dictionary approach was about 20x as slow.&lt;br /&gt;&lt;br /&gt;The Clojure persistent map did not perform as well as the FSharpMap, but still was much better than the mutable copy approach, and within an order of magnitude from having no history.  I am confident that the performance hit here is because I am doing some funky casting and/or reflection because I'm not providing type hints.  A true test would use an implementation in Clojure and avoid reflection.  I didn't go there as I wanted to keep the tests as similar as possible.&lt;br /&gt;&lt;br /&gt;Source code used to test is available here:&lt;br /&gt;https://github.com/timothypratley/timetraveltests&lt;br /&gt;I commented out the Clojure parts as you need to get the dependency to make that work.  If you want to, simply add Clojure as a reference and copy the clojure binaries into the output folder.  I suggest you build from source and match .NET framework targets.&lt;br /&gt;&lt;br /&gt;For a 5x time cost you can have an immutable dictionary with a fully recorded history.  Something that would take 20x as long if you had to copy the data around.  An important difference here is that the persistent map version uses shared structure and so will take up far less memory.  Too bad I don't know a good way to measure this.&lt;br /&gt;&lt;br /&gt;Yay for clever data-structures.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-8037018952681247314?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/8037018952681247314/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=8037018952681247314' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/8037018952681247314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/8037018952681247314'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2011/03/performance-testing-persistent-maps.html' title='Performance testing persistent maps'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-2420360229327929058</id><published>2010-02-15T16:44:00.000-08:00</published><updated>2010-03-10T14:09:59.537-08:00</updated><title type='text'></title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_XAJPzyj-Ugc/S3np6uAWnRI/AAAAAAAAAso/gR7euB_8q8k/s1600-h/Pizza_gameplay.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_XAJPzyj-Ugc/S3np6uAWnRI/AAAAAAAAAso/gR7euB_8q8k/s320/Pizza_gameplay.jpg" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;I was reminiscing about my youth and loaded up an old game I wrote in high school... Pizza Delivery! Totally a blast to play you drive around to flashing locations on the minimap to deliver pizzas and have to refuel occasionally. Going off the road makes your car blow up :)&amp;nbsp;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.kudosweave.com/downloads/pizza.zip"&gt;download pizza.zip&lt;/a&gt;&amp;nbsp;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-2420360229327929058?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/2420360229327929058/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=2420360229327929058' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2420360229327929058'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2420360229327929058'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2010/02/i-was-reminiscing-about-my-youth-and.html' title=''/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_XAJPzyj-Ugc/S3np6uAWnRI/AAAAAAAAAso/gR7euB_8q8k/s72-c/Pizza_gameplay.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-7362769361810533231</id><published>2010-01-04T15:12:00.000-08:00</published><updated>2010-01-04T16:42:55.019-08:00</updated><title type='text'>Examples are great value - 2 for the price of 1</title><content type='html'>Tests and documentation. Everyone is quick to label these as essential. But trying to include time for them in a project plan is always a battle. Tests and documentation are hard. But because they are seemingly easy to understand activities most people don't realize the effort and skill required to produce them. Even though these activities pay for themselves in the long run, they can end up the first thing on the chopping block when looking for things to cut from a project. This article provides a motivation as to why an example framework should be an integral part of development.&lt;br /&gt;&lt;br /&gt;Tests are great for making sure stuff works. &lt;a href="http://philip.greenspun.com/software/design-review"&gt;But tests and documentation are often the last thing on a programmers mind.&lt;/a&gt; Even if you have a testing regime in place, implementing &lt;a href="http://www.dalkescientific.com/writings/diary/archive/2009/12/29/problems_with_tdd.html"&gt;useful tests is actually quite an art&lt;/a&gt; that requires experience and thought.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Examples are a subset of tests.&lt;/b&gt;&lt;br /&gt;Actually examples are a &lt;i&gt;really important&lt;/i&gt; subset of tests because they inevitably are concerned with the API you are exposing, not the internals of your implementation. This is a very high payoff place to have tests. So much so you can think of examples as 'essential tests'. Not only does this mean they are important to provide, but it also means if you are providing examples then you are generating high value tests without additional deep thinking or experience required.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Examples make excellent documentation.&lt;/b&gt;&lt;br /&gt;Examples are a really great way to learn anything new. This is especially true in programming. Including examples in documentation of code communicates clearly what the code does and how it should be used. They also get the reader thinking about scenarios where they could use this stuff in ways that reading a description often does not convey.&lt;br /&gt;&lt;br /&gt;One thing people fear about documenting examples is 'what if they get out of date?'. Indeed this is a concern. But if our examples are really just important tests, then this concern disappears. Of course our examples will be kept up to date because we are using them as tests. Important tests that we need to pass. If we can achieve both testing and documentation from one activity the payoff to cost is much more appealing.&lt;br /&gt;&lt;br /&gt;Another concern is if the examples are too far removed from the code then they wont be created as part of the coding process. We want our development cycle to be closely knit with producing examples so these don't become a separate activate which could fall by the wayside. Performing documentation as a separate task rarely works well unless you have someone dedicated on the case. Documentation generated from source code improves the chance of survival.&lt;br /&gt;&lt;br /&gt;So here are my requirements for a useful example framework:&lt;br /&gt;&lt;ol&gt;&lt;li&gt; Define examples in one place once &lt;/li&gt;&lt;li&gt; Automatically part of test suite &lt;/li&gt;&lt;li&gt; Automatically included in documentation &lt;/li&gt;&lt;li&gt; Examples live in code &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;How might we achieve this in &lt;a href="http://clojure.org"&gt;Clojure?&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;First I'd like to note that all the parts are already there, which is great! Clojure has a built in test framework and an autodoc project which supports usage documentation.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Capture examples in workflow&lt;/b&gt;&lt;br /&gt;When developing a new function I always end up using it in some way and experimenting with it a little in a REPL. The first thing I do is write a function stub, then immediately after a very basic call to the function. From there I refine back and forward filling out the function, adding calls to it and fixing problems. Those experiments to just after the function definition then get turned into tests when I'm finished. Being able to do this is a really useful feature of Clojure. Clojure has an unfair advantage here being a functional language, it naturally lends itself to small discreet examples matching directly the function definitions.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What is missing?&lt;/b&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt; Unit tests do not automatically appear as usage in generated doc &lt;/li&gt;&lt;li&gt; Unit tests are user named and not related to symbols or available for lookup &lt;/li&gt;&lt;li&gt; Usage documentation is not tested, and is separate from the tests or code &lt;/li&gt;&lt;li&gt; Usage documentation is not available at the REPL via (doc) or (doc-usage) &lt;/li&gt;&lt;li&gt; Usage documentation coverage does not exist yet &lt;/li&gt;&lt;li&gt; There is no support for multiple usage or tests per symbol &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;These issues can all be overcome and I'm volunteering my help to address them. I've made a start on how I think this should be tackled and am now looking for feedback on whether these are useful improvements to make and the right approach to take.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://github.com/timothypratley/strive/blob/master/cljeg"&gt;The code is on github.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://github.com/timothypratley/strive/blob/master/cljeg/README.md"&gt;README&lt;/a&gt; describes what my goals are, what is remaining, and gives build instructions.&lt;br /&gt;&lt;br /&gt;The central part is an &lt;a href="http://github.com/timothypratley/strive/blob/master/cljeg/src/main/clojure/cljeg/example.clj"&gt;example macro&lt;/a&gt; which can used very similarly to deftest. The difference being it is associated to a symbol for lookup later from autodoc or (doc-usage) and has a slightly more restrictive form to more suit output formatting.&lt;br /&gt;&lt;br /&gt;I've implemented all the &lt;a href="http://github.com/timothypratley/strive/blob/master/cljeg/src/main/clojure/cljeg/examples.clj"&gt;wikibook examples&lt;/a&gt;. Now they are in s-expressions I am confident I can easily adapt them to a new system very easily.&lt;br /&gt;&lt;br /&gt;Lastly I want to re-iterate that Clojure already supports excellent test workflow and documentation. I've found it useful to myself to make some minor tweaks to achieve my goals. Now I'm at the (doc) lookup and autodoc generation part I want to more closely align with what Tom and Stuart are doing with the aim to help provide usage examples for Clojure itself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-7362769361810533231?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/7362769361810533231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=7362769361810533231' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/7362769361810533231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/7362769361810533231'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2010/01/examples-are-great-value-2-for-price-of.html' title='Examples are great value - 2 for the price of 1'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-2377950223219015313</id><published>2009-11-07T05:11:00.000-08:00</published><updated>2009-11-08T15:32:45.434-08:00</updated><title type='text'>Clojure's Quiet Achiever</title><content type='html'>The &lt;a href="http://clojure.org/sequences"&gt;sequence&lt;/a&gt; abstraction is at the heart of much of Clojure's power, but receives little attention. I want to tell you what's so great about it!&lt;br /&gt;&lt;br /&gt;Iteration and recursion are considered fundamental programming concepts and show up early in any 101 course no matter what the paradigm. The sequence abstraction almost completely throws these tools out the window. You don't need them. That's the big point I want to make here; this huge fundamental part of programming is unnecessary once you have a good sequence abstraction. I can't oversell how much complexity that removes. There must be a catch...&lt;br /&gt;&lt;br /&gt;By my count there are 80 functions in Clojure core for manipulating sequences in some way. When you first are exposed to them the natural reaction is a feeling that the cure is worse than the disease, that something simple like a loop is now a mammoth set of functions you need to learn and understand. Loops are just one thing, surely sequences are more complex. However consider for a moment that loops do lots of different things. You have to understand every loop you come across from start to end. Sequence functions abstract this away.&lt;br /&gt;&lt;br /&gt;A well worn example is (reduce * (range 2 10)) computes the factorial of 10. We have a sequence of number that need to be multiplied together, so we can express it like that instead of an iterative expression. Lots of languages support the heavy lifters map and reduce, so what's so special about Clojure? My premise is that Clojure has a fuller set of supporting functions which mean you almost never have to drop down to loop/recur. It also has lazy sequences and persistent data structures which mean it will be fast, and you don't need to worry about the implementation.&lt;br /&gt;&lt;br /&gt;Another simple example... Say we have a vector of numbers&lt;br /&gt;(def v [1 2 3 4 5])&lt;br /&gt;And we wanted to perform some operation on the sum of each item and the next item. We might implement this imperatively like so: &lt;br /&gt;for i=0; i&amp;ltv.length-1; i++&lt;br /&gt;operate( v[i] + v[i+1] );&lt;br /&gt;&lt;br /&gt;So how would this look like in sequence operations?&lt;br /&gt;(map operate (map + v (rest v)))&lt;br /&gt;&lt;br /&gt;Lets break that down,&lt;br /&gt;(rest v) the sequence of v without it's head: (2 3 4 5)&lt;br /&gt;we are mapping the + operator to two sequences: (1 2 3 4 5) and (2 3 4 5)&lt;br /&gt;which will result in a new sequence (3 5 7 9)&lt;br /&gt;which we map the operation over.&lt;br /&gt;&lt;br /&gt;You can read the statement as&lt;br /&gt;"create a sequence of results of calling operate on a sequence made from adding items from a sequence of v to a sequence of v without it's head."&lt;br /&gt;user=&gt; (map inc (map + v (rest v)))&lt;br /&gt;(4 6 8 10)&lt;br /&gt;&lt;br /&gt;The parts can be individually understood. They can be combined to perform pretty much anything you need to do. As individual pieces they are simple enough to understand and make building blocks to describe all sorts of transformations. This is true of all means of abstraction and means of combination, and especially true of functional abstractions. The sequence abstraction can be extended also. Check out &lt;a href="http://github.com/ato/clojure-utils/blob/master/src/org/meshy/seq_utils.clj"&gt;this interesting library&lt;/a&gt; which allows you to do SQL like queries on sequences.&lt;br /&gt;&lt;br /&gt;Clojure really exploits the sequence abstraction well to remove a major source of mutation and state: iteration/recursion. Sequences are built into the language and well supported with many useful utility functions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-2377950223219015313?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/2377950223219015313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=2377950223219015313' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2377950223219015313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2377950223219015313'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2009/11/clojures-quiet-achiever.html' title='Clojure&apos;s Quiet Achiever'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-8078014613945565046</id><published>2009-11-07T04:37:00.000-08:00</published><updated>2009-11-07T04:37:54.721-08:00</updated><title type='text'>Live long Java</title><content type='html'>One thing I really love about Java is the quality of its libraries. The famous Java Ecosystem. For just about any problem domain you'll be able to pickup something that works great and is well supported. Most of the time you wont even need to leave the massive standard library. They really do have something for everyone. And usually there is a pretty clear winner so you don't have to spend your time trialling solutions or wondering how to integrate them.&lt;br /&gt;&lt;br /&gt;Lets look at client/server communications for example. Sockets socket sockets, so much fun to be had! So many choices to be made. Will you use threads? Will you support TSL? What wire format to choose? Are you after performance, or simplicity? Yes you can tackle all those problems with due vigor, but someone already has! &lt;a href="http://www.jboss.org/netty"&gt;Netty&lt;/a&gt; gives you a completely configurable framework so you can treat all those decisions as options and just focus on your client/server protocol. This is no small thing, decoupling your messaging from the transport layer. For example UDP and TCP are totally different abstractions and it is a non-trivial task to come up with a solution which allows you to plug in either and still work.&lt;br /&gt;&lt;br /&gt;Java really has reached a very strong level of 'this is how you solve that problem'. And for that, I hope it stays around for a long time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-8078014613945565046?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/8078014613945565046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=8078014613945565046' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/8078014613945565046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/8078014613945565046'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2009/11/live-long-java.html' title='Live long Java'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-7234015689245260057</id><published>2009-11-04T05:40:00.000-08:00</published><updated>2009-11-04T05:40:46.244-08:00</updated><title type='text'>Believe the computer</title><content type='html'>If you support software you are probably familiar with this scenario:&lt;br /&gt;&lt;br /&gt;A person responsible for system X seeks your help because "System Y is broken because it is reporting problem Z with X". The general premise is that it must be System Y's fault, because X is not reporting any error. You respond "X has problem Z". But they can't find any problem Z, it must be Y. Well it is true, Y is not infallible, it could be reporting incorrectly or not doing the right thing. You check the logs, follow the interactions, check any values/times/events... and come to the conclusion "Y indicates X has problem Z". After explaining your findings, they fix Z in X. I've been on both sides of the equation.&lt;br /&gt;&lt;br /&gt;Why do we find it so hard to imagine an error occurring on 'our' end? Well if we could imagine the error, we would already be on the path to fix it. Also sometimes checking the 'other end' quickly reveals something outside your control. The second reason is however a big red warning flag. If 'this end' does not provide enough information to tell you whether it is successfully interacting with some other system, it is time to add that feature. This is the first step to being able to diagnose this problem and avoid getting caught in the same cycle for the next one. Once you have that information, you are one step closer to imagining the real cause.&lt;br /&gt;&lt;br /&gt;This topic is closely related to the phenomenon whereby when stuck with a seemingly unsolvable problem, simply telling someone else about it can point out an answer without any input from the other person. Some workplaces find this so compelling they set up a doll or teddy bear that developers have to speak to before they ask any one else. The great thing about computer systems is they can be vastly more informative than teddy bears. If you believe them!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-7234015689245260057?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/7234015689245260057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=7234015689245260057' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/7234015689245260057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/7234015689245260057'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2009/11/believe-computer.html' title='Believe the computer'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-343981697110145771</id><published>2009-09-16T17:50:00.000-07:00</published><updated>2009-09-16T17:50:52.661-07:00</updated><title type='text'>Prefix niggle: Comparators</title><content type='html'>Infix comparators are very intuitive:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;x &lt; y&lt;/code&gt;&lt;/pre&gt;Which reading literally sounds like "x is less-than y". Visually the arrow indicates we are testing for x being smaller than y.&lt;br /&gt;&lt;br /&gt;Prefix notation for comparators has always been something hard for me to think about:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(&lt; x y)&lt;/code&gt;&lt;/pre&gt;Reading literally sounds like "less-than x y", which takes a bit of mental untangling. Visually it requires a bit of cognition to distinguish &lt; is less-than and &gt; is greater-than because there is no context.&lt;br /&gt;&lt;br /&gt;However if instead of calling &lt; "less-than?", we call it "ascending?" then grammatically the sentence become much easier to understand: "ascending? x y". Also the arrow is more easily interpreted visually as we don't require any context to consider it to be a ramp ascending &lt; or a ramp descending &gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-343981697110145771?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/343981697110145771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=343981697110145771' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/343981697110145771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/343981697110145771'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2009/09/prefix-niggle-comparators.html' title='Prefix niggle: Comparators'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-2976734359196492038</id><published>2009-08-19T16:42:00.000-07:00</published><updated>2009-08-26T04:20:55.180-07:00</updated><title type='text'>Why learn Clojure?</title><content type='html'>Clojure is expressive and powerful. It provides the concise expression capabilities of Lisp in a practical environment. It also leverages the JVM, anything you can do in Java you can do in Clojure with far less ceremony. There are loads of other reasons but lets dive into some syntax to get a feel for the language.&lt;br /&gt;&lt;br /&gt;Clojure programs are written in forms. Forms enclosed in parenthesis indicate function calls:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(+ 1 2 3)&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;calls the '+' function with arguments 1 2 3 and returns the value 6, the sum of arguments.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;New functions can be defined using defn:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(defn average [x y] (/ (+ x y) 2))&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Here x and y are symbols representing the input arguments.&lt;br /&gt;Function '/' is called to divide the sum of x and y by 2.&lt;br /&gt;Note that forms are always in prefix notation, with function followed by subsequent arguments.&lt;br /&gt;Now average can be invoked as&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(average 3 5)&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;and will return 4.&lt;br /&gt;In this example, 'average' is a symbol, whose value is a function.&lt;br /&gt;&lt;br /&gt;Clojure provides easy access to the JVM:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(.show (javax.swing.JFrame.))&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;This calls the show method on the result of (javax.swing.JFrame.) which constructs a new Jframe. Note the full stop before the method call and the full stop after the construction. We can combine them without the usual boilerplate code:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(doto (javax.swing.JFrame.)&lt;br /&gt;  (.setLayout (java.awt.GridLayout. 2 2 3 3))&lt;br /&gt;  (.add (javax.swing.JTextField.))&lt;br /&gt;  (.add (javax.swing.JLabel. "Enter some text"))&lt;br /&gt;  (.setSize 300 80)&lt;br /&gt;  (.setVisible true))&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Functions can be passed to other functions:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(map + [1 2 3] [4 5 6])&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;returns (5 7 9)&lt;br /&gt;map is a function which takes another function and calls it with arguments taken from following collections. In our case we have provided the function '+' and two vectors of integers. The result is a list of the results of calling '+' with arguments taken from the vectors. Using functions as arguments to other functions is very powerful. We can use our previously defined average function with map like so:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(map average [1 2 3] [4 5 6])&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;returns (5/2 7/2 9/2)&lt;br /&gt;&lt;br /&gt;Functions can also return other functions:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(defn addx [x] (fn [y] (+ x y)))&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Here addx will return a new function that takes 1 argument and adds x to it.&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(addx 5)&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;returns a function that can be called with 1 argument and will add 5 to it.&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(map (addx 5) [1 2 3 4 5])&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;returns (6 7 8 9 10)&lt;br /&gt;We called map with a the result of addx, which was a function that takes an argument and adds 5. That function was called on the list of numbers we supplied.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(reduce + (range 1 100 2))&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;(range 1 100 2) creates a lazy sequence of numbers 1 3 5 7 ... 99. 1 is the starting point, 100 is the end point, 2 is the step. reduce calls the + function. First it calls + with two arguments, the first two numbers supplied by range. Then it calls + again with the previous result and the next number, until all the numbers are exhausted. Clojure has lots of support for sequences, collections and high level operations. As you learn them, you will find very expressive ways to write tasks such as this.&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(defn factorial [n]&lt;br /&gt;  (reduce * (range 2 (inc n))))&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Clojure provides hash-maps which are very useful in many programming tasks. Maps are written between {} just like vectors are written between [] and lists are written between ().&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;{:name "Tim", :occupation "Programmer"}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Is a map which associates the keyword :name with "Tim" and :occupation with "Programmer". Note that the comma is treated as whitespace by Clojure but may be optionally supplied to help visually group things that go together. Keywords are preceeded by : and provide a convenient way to name fields, however keys don't have to be keywords.&lt;br /&gt;&lt;br /&gt;assoc returns a new map with a value associated to a key:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;user=&gt; (assoc {:a 1, :b 2} :b 3)&lt;br /&gt;{:a 1, :b 3}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(defn map-count [map key]&lt;br /&gt;(assoc map key (inc (get map key 0))))&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;This function takes a map as input, looks up a key and increments how many times that key has been counted. (get map key 0) just looks up key in map and returns its value if found, else 0. inc adds one to that value. (assoc map key value) will return a new map with key associated to value. So as you can see the map is not modified in any way. A new map is returned with a new value associated to the key supplied.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(reduce map-count {} ["hi" "mum" "hi" "dad" "hi"])&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Results in {"dad" 1, "mum" 1, "hi" 3} because reduce starts with an empty map which is used as the input to the first function call, then the resulting map is used for the next and so forth. The strings are used as keys. Now we can write a more useful function which takes a string and counts the words in it:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;(defn count-words [s]&lt;br /&gt;  (reduce map-count {}&lt;br /&gt;          (re-seq #"\w+" (.toLowerCase s))))&lt;br /&gt;(count-words "hi mum hi dad hi")&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Gives the same result. Note that re-seq here splits the input string into words based upon the regular expression provided.&lt;br /&gt;&lt;br /&gt;This should have given you a taste of the syntax and the power of&lt;br /&gt;&lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt;.&lt;br /&gt;Try it out!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-2976734359196492038?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/2976734359196492038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=2976734359196492038' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2976734359196492038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2976734359196492038'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2009/08/clojure-programs-are-written-in-forms.html' title='Why learn Clojure?'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-2822946050462035020</id><published>2009-05-26T06:49:00.000-07:00</published><updated>2009-05-26T07:46:44.727-07:00</updated><title type='text'>Rational choice</title><content type='html'>Science has answered many questions and illuminated many truths. As our understanding of nature expands it becomes clearer that our existence is explainable by the physical properties of our universe. Taking this further, our existence is actually defined by these properties. Being fully defined, how can a rational mind believe in choice?&lt;br /&gt;&lt;br /&gt;At my will, I can think to bend my arm, and then I bend my arm, and it bends. Surely this is proof of choice? Did I not just choose to do and execute that choice? Well actually my brain state interacted with my muscles by firing electrical currents. This current was triggered by a chemical process, driven by physical molecules. Those interactions all colluded to result in my arm moving. What part did I play in it? The event happened, I precipitated the event. Or did I just observe it? All these questions are turning away from choice and focusing on understanding what the "I" label means.&lt;br /&gt;&lt;br /&gt;As we chase the cause and effect trying to determine what originated the choice we soon run out of sources within our own body. The event was influenced by our environment, which was a result of our upbringing, and before that our genes. Everything leading to the event of me bending my arm was a beautiful, logarithmically complex chain of events from the big bang, expansion of the cosmos, formation of RNA, formation of life, evolution, on a scale of time that is incomprehensible. It was all inevitable. There is only one outcome. What appears to be random is just our lack of understanding. An understanding that can never be reached because its only manifestation is its entirely.&lt;br /&gt;&lt;br /&gt;When you watch a river flow, you can spot eddies and patterns in the water. You are looking at completely different water but the shape of the bank causes these patterns to persist. Complex shapes and dances form. We ourselves are similar. We appear as an entity in full self control, but actually we are entirely a result of a universal history. Our bodies are just cells which have developed in a symbiosis which allowed them to grow. Our thoughts occurring in the neural network of our chemical brain. Most of the molecules are transients from eating, drinking and breathing which get absorbed transformed and ejected continuously. Even our digestion is governed by bacterial processes which come from entirely external sources. Everything about us is governed by causes and effects that we cannot fully measure, but which are bound by the laws of physics like some giant game of dominoes.&lt;br /&gt;&lt;br /&gt;So we are observers it seems. Conscious enough to watch the movie but even our own actions are the result of processes that cannot be controlled. The script is unknown to us, but is already fully determined and unchangeable.&lt;br /&gt;&lt;br /&gt;Pick a religion and it comes up empty on the question of choice also. It is possible to conceptualize ourselves as some kind of supernatural dice machine with a mystical link to the physical world. Even so, that would remove all possibility of the rationality required to make a choice and reduce it to a random event.&lt;br /&gt;&lt;br /&gt;So how can a rational mind believe in choice?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-2822946050462035020?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/2822946050462035020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=2822946050462035020' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2822946050462035020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2822946050462035020'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2009/05/rational-choice.html' title='Rational choice'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-6685667972654087295</id><published>2008-07-10T19:09:00.000-07:00</published><updated>2008-07-10T19:16:29.942-07:00</updated><title type='text'>Simple stuff for Linux</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Man(ual) pages&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;To get help on a particular command:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;$ man &lt;/span&gt;&lt;command&gt;&lt;br /&gt;eg. man printf&lt;br /&gt;Man stands for manual. It is split in to sections.&lt;br /&gt;&lt;br /&gt;Section #    Topic&lt;br /&gt;1    Commands available to users&lt;br /&gt;2    Unix and C system calls&lt;br /&gt;3    C library routines for C programs&lt;br /&gt;4    Special file names&lt;br /&gt;5    File formats and conventions for files used by Unix&lt;br /&gt;6    Games&lt;br /&gt;7    Word processing packages&lt;br /&gt;8    System administration commands and procedures&lt;br /&gt;&lt;br /&gt;In the example above it pulls the printf man page from the shell which is most likely not the one wanted.&lt;br /&gt;So run:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;$ man 3 printf&lt;/span&gt;&lt;br /&gt;to get the C library printf routine&lt;br /&gt;To quit from a man page, press "q"&lt;br /&gt;To search a man page, type "/&lt;search&gt;"&lt;br /&gt;&lt;br /&gt;To search the man pages&lt;br /&gt;&lt;span style="font-style: italic;"&gt;$ apropos &lt;/span&gt;&lt;search&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Shell shortcuts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;^D         - logout&lt;br /&gt;cd -        - return to the previous directory you were in&lt;br /&gt;!$         - use the last arguement from the previous command&lt;br /&gt;(ctrl)c - cancel a command&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Unix utilities&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To search through all the .h files in the projects directory and directories below for the definition of "Cont_"&lt;br /&gt;&lt;span style="font-style: italic;"&gt;find ~/projects -name "*.h" -exec grep -H "typedef struct Cont_" {} \; -print&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;Use awk to print one column from a text file.&lt;br /&gt;eg: Given a file, ctr.log, with lines like&lt;br /&gt;ctr key: 1983224, iso: 2210, ctr no: TTNU1519344 , etd: 1215752400&lt;br /&gt;ctr key: 1983225, iso: 22G1, ctr no: FSCU3621588 , etd: 1215752400&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;$ grep "iso: 22G1" ctr.log | awk ' { print $8 } ' | sort | uniq&lt;/span&gt;&lt;br /&gt;This will find all of the containers with the iso 22G1 in the ctr.log file; print the 8th column, the container number; sort them and remove any duplicates.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;$ grep "iso: 22G1" ctr.log | wc -l&lt;/span&gt;&lt;br /&gt;This will count how many 22G1 containers there are by counting the number of lines.&lt;/search&gt;&lt;/search&gt;&lt;/command&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-6685667972654087295?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/6685667972654087295/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=6685667972654087295' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/6685667972654087295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/6685667972654087295'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2008/07/simple-stuff-for-linux.html' title='Simple stuff for Linux'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-4959553074621769897</id><published>2008-07-03T03:24:00.000-07:00</published><updated>2008-07-14T23:19:08.062-07:00</updated><title type='text'>CVS</title><content type='html'>&lt;a href="http://www.cs.utah.edu/dept/old/texinfo/cvs/cvs_toc.html"&gt;&lt;span style="font-weight: bold;"&gt;Usage&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;cvs -d (repository) login&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;cvs -d (repository) checkout (module&lt;/span&gt;)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;cvs update&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;cvs diff&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;cvs commit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;NB: you can also shorten usage, eg: cvs up works just like cvs update.&lt;br /&gt;&lt;br /&gt;I recommend always doing a cvs diff before any commits. This shows you exactly what you have changed and will be committing, and can avoid accidentally introduced typos.&lt;br /&gt;&lt;br /&gt;Avoid mixing formatting changes with logic changes. Doing so makes it very difficult to figure out exactly what changed. Formatting changes typically effect large portions of the file but have no impact on the meaning of the file. Logic changes typically effect only small portions of the file but greatly effect behavior of the program you are editing. If you mix them, cvs tools wont be able to help you discover what really changed to cause some new behaviour. So avoid making formatting changes, and batch them up into one big commit which changes nothing but the format. This works well with indentation tools such as &lt;a href="http://astyle.sourceforge.net/"&gt;astyle&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Checking changes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;cvs annotate (file) &gt; tmp&lt;/span&gt;&lt;br /&gt;Will create you a replica of the file, marked with the person who last changed each line, and what date they made the change. This is useful for finding out who is responsible for some part of the code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;cvs log (file)&lt;/span&gt;&lt;br /&gt;Gives you the list of revisions, who made them and when.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;cvs diff -r (revision) (file)&lt;/span&gt;&lt;br /&gt;Shows you the differences between the current file, and what it was as of the specified revision. This is useful when trying to figure out what has been introduced into a new version if you are looking for an obscure bug.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-4959553074621769897?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/4959553074621769897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=4959553074621769897' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/4959553074621769897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/4959553074621769897'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2008/07/cvs.html' title='CVS'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-1097740310946382571</id><published>2008-07-03T03:08:00.000-07:00</published><updated>2008-11-05T21:06:42.902-08:00</updated><title type='text'>Debugging</title><content type='html'>&lt;a href="http://sourceware.org/gdb/current/onlinedocs/gdb_toc.html"&gt;GDB&lt;/a&gt; can really be a life saver, even if used for only the most basic functions.&lt;br /&gt;&lt;br /&gt;When programs crash they create a core file (sometimes you need to do some configuration to ensure this happens and what the file is called).&lt;br /&gt;&lt;span style="font-style: italic;"&gt;gdb myprog core&lt;/span&gt;&lt;br /&gt;(This loads the information dumped when the program crashed)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;bt&lt;/span&gt;   (or backtrace)&lt;br /&gt;provides the call stack when the error occured. It shows you exactly on which line of which file the problem occured (if you have debug symbols).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;info locals&lt;/span&gt;&lt;br /&gt;prints out information about local variables, usually at this point you will go oh damn that should not be NULL, and realize what needs to be fixed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;print &lt;/span&gt;&lt;variable&gt;&lt;span style="font-style: italic;"&gt;myvariable&lt;/span&gt;&lt;br /&gt;if you want to check a particular variable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;up&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;down&lt;/span&gt;&lt;br /&gt;move up or down the stack to look at variables in a different scope.&lt;br /&gt;&lt;br /&gt;If you are writting a service, you can create a script that loads a core and does a bt and info locals and emails you. For example:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;                # See if there was a crash&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;                corefile=/var/crash/corefiles/core.${PROCESS}.$UID.$pid&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;                if [ -f $corefile ]; then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;                    gdb $bindir/${PROCESS} $corefile &lt; $basedir/sh/gdb_script &gt; mail.out&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;                    mail -s "${PROCESS} crashed" me@email.com &lt;&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;                    rm mail.out&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;                fi&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;Where gdb_script just contains:&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;                backtrace&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;                info locals&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;Sometimes (especially with &lt;a href="http://yosefk.com/c++fqa"&gt;C++&lt;/a&gt;) the stack gets corrupted and provides no information. Now you have to either resort to printfs in the code, interactive GDB or use electric-fence/valgrind.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Logging&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you are writting a non-trivial program, chances are you have a log file that you write to. The more useful information you have in the log, the less hit and miss you have to do to narrow down the problem. A big part of this usefulness is simply choosing unique and searchable strings for your output, and formatting the information in ways that make it relatively easy to grep for. Some people like to put file/function/line information in the log. This can be useful, but my preference is to stick with a timestamp and a concise, unique message which includes not only a description of the event, but any id information associated linked to the event. I never have the same log string twice in a program if I can help it.&lt;br /&gt;&lt;br /&gt;Two things that will save you hours of pain are:&lt;br /&gt;1) Always expect the worst, always check for bad inputs or undefined cases and at the very least write an error message to your log file. Always check that pointers passed into a funciton are not NULL before dereferencing, always check for indices outside the array bounds, elses in if trees and defaults in case statements. In large projects the unexpected always happens and the sooner you can localise where, the better. If your program doesn't handle it, at least you KNOW about it and can fix it.&lt;br /&gt;2) Write to the log file regularly. A good rule of thumb for me is whenever processing something external, changing state, or responding to some event. The more information you have about what happened leading up the the problem the better. What you don't want is repeatitive or overly verbose spam, as it can bury the real information. However so long as you use unique strings, you can usually use text processing techniques to quickly dig up what you want.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Less is better than VIM for log files&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A final note on using log files: Use &lt;span style="font-style: italic;"&gt;less &lt;/span&gt;to read them.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;less &lt;/span&gt;is a command just like more, but is ironically much more powerful.&lt;br /&gt;It has all the searching functionality of VIM, but is a better choice than VIM because if your log file is large (which it will be) VIM uses vast system resources (memory, tempory files) and is slow to load.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;Some common shortcuts you should know [work in less and VIM]:&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;(shift)G&lt;/span&gt;    -&lt;/span&gt;&lt;span&gt; goto end of file&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;?(string)&lt;/span&gt;    -&lt;/span&gt;&lt;span&gt; search backward for (string)&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;/(string) &lt;/span&gt;   -&lt;/span&gt;&lt;span&gt; search forward for (string)&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;n&lt;/span&gt;    - &lt;/span&gt;&lt;span&gt;repeat last search (in last direction)&lt;br /&gt;If you press shift+F, it will start acting like "tail -f". You can stop auto refreshing by Ctrl+C&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Keep a seperate editor open that you can copy and paste important lines into. This allows you to build up a timeline of important events which will allow you to understand why the impossible has happened.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/variable&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-1097740310946382571?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/1097740310946382571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=1097740310946382571' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/1097740310946382571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/1097740310946382571'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2008/07/debugging.html' title='Debugging'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-2743890795480425080</id><published>2008-07-03T02:43:00.000-07:00</published><updated>2008-07-03T23:10:07.597-07:00</updated><title type='text'>Building with Makefiles</title><content type='html'>Always compile with warnings on!&lt;br /&gt;&lt;span style="font-style: italic;"&gt;gcc -Wall foo.c&lt;/span&gt;&lt;br /&gt;The -Wall means Warn all. Without it you will have subtle flaws in your program that will be impossible to debug. Behavior that just does not make sense because of some trivial syntax or cast precision loss. It does not take a lot of effort to produce warning free code, but it does take a lot of effort to find a bug that the compile could have told you about. You will also learn quite a lot about the subtleties C/C++ in a controlled environment, instead of the lost in the wilderness with wild animals way.&lt;br /&gt;&lt;br /&gt;Build &lt;a href="http://timothypratley.blogspot.com/2008/07/debugging.html"&gt;debug symbols&lt;/a&gt; (-g), you wont regret it when you get a phone call at 2am in the morning.&lt;br /&gt;&lt;br /&gt;Use compiler optimisation (-O1 -O2 or -O3), it really does improve performance dramatically.&lt;br /&gt;&lt;br /&gt;When in doubt, make clean.&lt;br /&gt;Often you are working with other people's make files. Maybe edited by multiple people afterward. They or you might not have set the dependencies up in a fool proof manner, resulting in a broken build. If you have library dependencies, make clean;make on those too! Spend some time reading &lt;a href="http://www.yosefk.com/blog/redundancy-vs-dependencies-which-is-worse.html"&gt;yosefk&lt;/a&gt; if you are depressed about this and need cheering up. But quite often if you are having some weird problem it is a broken build. Make clean will either fix it or at least give a compile error as to what is wrong. (eg: a function might have been redefined with different arguments, but if the .o is not rebuilt you will link to it incorrectly and crash!)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://aegis.sourceforge.net/auug97.pdf"&gt;Makefiles&lt;/a&gt; can be complicated things, but really we want them to do something very simple: If anything changes, recompile it! Dependencies can be generated for you to do this, so you don't need to sit there figuring them out.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;gcc -MMD &lt;/span&gt;&lt;blah&gt;&lt;br /&gt;creates a .d file for all your &lt;blahs&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;-include $(OBJS:.o=.d)&lt;/span&gt; will include these dependency files (if they exist, and the .o can't exist if they don't) so this will always keep you up to date and avoid make clean paralysis.&lt;br /&gt;&lt;br /&gt;You can make rules to automatically compile your stuff for you. Check this out, it even puts the .o files and .d files into an obj directory so it wont clutter up your filesystem:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;$(OBJDIR)/%.o: %.cpp Makefile&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;       @$(RM) -f $@&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;       @mkdir -p $(DIRS)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;       $(CPP) -MMD $(CFLAGS) $(INCLUDE) -c $&lt; -o $@ 2&gt;&amp;amp;1 | more&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you are lazy it can even find all your source files to compile:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;SRCS = $(shell find -name 'tests' -prune -o -name '*.cpp' -printf "%P ")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;DIRS = $(shell find \( -name 'CVS' -o -name '$(OBJDIR)' -o -name 'tests' \) -prune -o -type d -printf "$(OBJDIR)/%P ")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;OBJS = $(patsubst %.cpp,$(OBJDIR)/%.o,$(SRCS))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;However sometimes it is preferable to be able to specify the source manually if you have multiple executables to build.&lt;/blahs&gt;&lt;/blah&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-2743890795480425080?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/2743890795480425080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=2743890795480425080' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2743890795480425080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2743890795480425080'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2008/07/building-with-makefiles.html' title='Building with Makefiles'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-2385283774806921058</id><published>2008-07-03T02:04:00.000-07:00</published><updated>2008-07-03T23:14:53.086-07:00</updated><title type='text'>VIM</title><content type='html'>&lt;a href="http://www.tuxfiles.org/linuxhelp/vimcheat.html"&gt;VI(M)&lt;/a&gt; is a very powerful editor which requires you to survive a learning period as it is different from almost any interface you have used before. If you survive, you will love it, if not you will hate it.&lt;br /&gt;&lt;br /&gt;So lets us vi a file right now!&lt;br /&gt;&lt;span style="font-style: italic;"&gt;vi test.txt&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first thing that whacks you in the face is that you cannot type text into your document! Why? VI has two modes:&lt;br /&gt;1) command mode&lt;br /&gt;2) edit mode&lt;br /&gt;And you initially start in command mode. You can enter edit mode by pressing 'i'. Now you can type into the document. You can always get back to command mode by pressing escape. Back in command mode you can type :x to exit and save. That is the major hurdle that most people don't jump. There are plenty of good VIM documents on the web explaining basic usage to build on from there.&lt;br /&gt;&lt;br /&gt;Here are some development specific tips once you are comfortable with VIM as an editor which make it far more productive than an IDE:&lt;br /&gt;&lt;br /&gt;Use &lt;a href="http://timothypratley.blogspot.com/2008/07/ctags.html"&gt;ctags&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you were recently editing but navigated away and want to go back to where you were, press u for undo then (ctr)r for redo.&lt;br /&gt;&lt;br /&gt;Use .&lt;br /&gt;This is 'repeat last command'&lt;br /&gt;Suppose you called a variable 'notvalid' and then later decided you wanted it to be 'isvalid':&lt;br /&gt;&lt;span style="font-style: italic;"&gt;/notvalid&lt;/span&gt;&lt;br /&gt;(searches forward for occurance of notvalid)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;cw !isvalid&lt;/span&gt;&lt;br /&gt;(change word - replaces notvalid with !isvalid)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;(esc)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;/&lt;/span&gt;&lt;br /&gt;(search again)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;.&lt;/span&gt;&lt;br /&gt;(repeat last command - this will replace the notvalid we just found with !isvalid)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;.&lt;/span&gt;&lt;br /&gt;(and again)&lt;br /&gt;&lt;br /&gt;Of course you could also use a global search and replace:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;:%s/notvalid/!isvalid/g&lt;/span&gt;&lt;br /&gt;Which is less typing, but I prefer to check each replace as I go, so the search and repeat is good for that. You can do very complex editing very quickly using this technique, just by putting a little thought into how to modify text in a repeatable way.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;:make&lt;/span&gt;&lt;br /&gt;will build your project from within VIM. The advantage of this is that it will take you instantly to the line and file of any error that might occur in the build.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;:cn&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;:cp&lt;/span&gt; can be used to move forward and backward through the error messages.&lt;br /&gt;&lt;br /&gt;Customise your ~/.vimrc&lt;br /&gt;This is what will transform VIM into a customised IDE.&lt;br /&gt; &lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;syntax on&lt;/span&gt;&lt;br /&gt;Will do syntax highlighting&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set viminfo='10,\"100,:20,%,n~/.viminfo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;   au BufReadPost * if line("'\"") &gt; 0|if line("'\"") &lt;= line("$")|exe("norm '\"")|else|exe "norm $"|endif|endif&lt;/span&gt;&lt;br /&gt;Will remember the last line you were in when you lasted edited a file.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;set expandtab&lt;/span&gt;&lt;br /&gt;Is usually the easiest way to ensure tab size is irrelevant.&lt;br /&gt;&lt;br /&gt;set smartcase&lt;br /&gt;Will allow you to search for strings case-insensitive unless you use capitals. There are many more handy ones, look up the documentation and go nuts!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set autoindent&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set smartindent&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set softtabstop=4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set shiftwidth=4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set showmatch&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set ruler&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set incsearch&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set ignorecase&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set number&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set cindent&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set backspace=2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set laststatus=2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;%&lt;/span&gt;&lt;br /&gt;If you press this while over a brace, it will take you to the complimentary brace. This is a life saver if the code isn't formatted how you like it and you can't be sure what nest you are in.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;(shift)G&lt;/span&gt;&lt;br /&gt;Go to end of file&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;?&lt;/span&gt;&lt;br /&gt;search backward&lt;br /&gt;&lt;br /&gt;/(up) or %(up) or ?(up)&lt;br /&gt;each time you press (up) it goes back to the previous string so you can modify it. (down) goes forward through the list.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;I&lt;/span&gt;&lt;br /&gt;insert at start of line&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;A&lt;/span&gt;&lt;br /&gt;append at end of line,&lt;br /&gt;just press &lt;span style="font-style: italic;"&gt;(esc)&lt;/span&gt; after if you dont want to put any text in&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;8yy&lt;/span&gt;&lt;br /&gt;(navigate)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;p&lt;/span&gt;&lt;br /&gt;Will copy 8 lines and paste it where you want it&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;8dd&lt;/span&gt;&lt;br /&gt;Will delete 8 lines of code&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;8(down)&lt;/span&gt;&lt;br /&gt;Will move down 8 lines&lt;br /&gt;I use this to measure how much I want to cut copy or delete.&lt;br /&gt;Alternatively you can use visual select mode&lt;br /&gt;&lt;span style="font-style: italic;"&gt;(ctrl)v&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-2385283774806921058?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/2385283774806921058/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=2385283774806921058' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2385283774806921058'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2385283774806921058'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2008/07/vim.html' title='VIM'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32811356.post-2211808559840715223</id><published>2008-07-03T01:19:00.000-07:00</published><updated>2008-07-03T22:55:55.930-07:00</updated><title type='text'>ctags</title><content type='html'>&lt;a href="http://ctags.sourceforge.net/faq.html"&gt;ctags&lt;/a&gt; allow you to quickly navigate source code by jumping to the definition of a tag (eg: a function or variable declaration). This is vital on large projects, as without it you are stuck with grep or find.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:courier new;" &gt;ctags -R&lt;/span&gt;&lt;br /&gt;will recursively build a tags file which is recognised by VIM (and other editors). Now if you edit a source file, you will be able to press (ctrl)] to jump to the definition of a tag, and (ctr)t to return back to where you were.&lt;br /&gt;&lt;br /&gt;You need to keep the tags up to date, so in your Makefile add the following rule:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;tags: $(SRCS) Makefile&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;        -ctags -R&lt;/span&gt;&lt;br /&gt;This will rebuild the tags if any of your source files change.&lt;br /&gt;&lt;br /&gt;Large projects typically have nested directories. By default VIM does not search up for a central tags file, but you can make it do this by adding to your ~.vimrc&lt;br /&gt;&lt;span style="font-style: italic;"&gt;set tags=tags;/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What doesn't work too well is if your project depends on an external library. If the library is part of your source tree you can have a top level tags file, however how to keep this up to date is unknown to me. Also you will run into duplicate tags which your editor may or may not deal with nicely.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32811356-2211808559840715223?l=timothypratley.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timothypratley.blogspot.com/feeds/2211808559840715223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32811356&amp;postID=2211808559840715223' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2211808559840715223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32811356/posts/default/2211808559840715223'/><link rel='alternate' type='text/html' href='http://timothypratley.blogspot.com/2008/07/ctags.html' title='ctags'/><author><name>timothypratley</name><uri>http://www.blogger.com/profile/11081038249454453409</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_XAJPzyj-Ugc/SG3CZTymB2I/AAAAAAAAAPc/T9jJXb0JSnE/S220/timhead.PNG'/></author><thr:total>0</thr:total></entry></feed>
