From 69b748b593efe7f8309d540dea1a1c02aafdb903 Mon Sep 17 00:00:00 2001 From: Ariejan de Vroom Date: Wed, 7 Feb 2024 11:02:23 +0100 Subject: [PATCH] Organize posts in year folders --- .../2006-10-09-welcome-to-ariejannet.md | 0 ...06-10-10-easily-create-a-favicon-online.md | 0 ...10-10-generate-a-sqlite-based-rails-app.md | 0 ...10-10-hi-res-wallpapers-for-you-macbook.md | 0 .../2006-10-10-top-5-dvds-you-must-have.md | 104 +- .../2006-10-13-having-fun-with-spam.md | 0 ...6-10-13-migrate-sqlite3-to-mysql-easily.md | 0 .../2006-10-13-tagging-in-ajax_scaffold.md | 0 ...006-10-23-ruby-on-rails-for-php-cakephp.md | 0 ...-29-do-your-ads-pay-your-blogging-bills.md | 0 .../2006-10-30-adsense-resource-inventory.md | 0 .../2006-10-30-cheat-sheets-look-here.md | 0 .../2006-10-30-confused-about-css-columns.md | 0 .../2006-10-30-how-does-your-site-look-on.md | 0 ...-10-31-wordpressmu-dont-allow-new-blogs.md | 0 .../2006-11-13-cups-426-upgrade-required.md | 0 ...buntu-610-live-dvd-on-the-apple-macbook.md | 0 ...se-tool-deploy-you-google-cse-with-ease.md | 0 .../2006-11-21-cse-tool-110-released.md | 0 ...21-svn-how-to-release-software-properly.md | 0 ...-project-hosting-sourceforge-competitor.md | 0 ...2006-11-22-svn-how-to-fix-bugs-properly.md | 0 ...2-wordpress-author-comment-highlighting.md | 0 ...24-svn-how-to-structure-your-repository.md | 0 ...he-three-corner-stones-of-developerhood.md | 0 .../2006-11-30-rails-security-check-up.md | 0 ...etup-a-ubuntu-development-server-part-1.md | 0 ...etup-a-ubuntu-development-server-part-2.md | 0 ...-installing-rails-on-ubuntu-dapper-edgy.md | 0 ...nstall-ruby-mysql-on-mac-os-x-104-tiger.md | 0 ...-current-svn-revision-in-your-rails-app.md | 0 ...6-12-20-svn-how-often-should-you-commit.md | 0 ...2-20-svn-merge-a-branch-with-your-trunk.md | 0 ...materails-easy-partials-for-better-code.md | 2 +- ...ls-group-results-by-week-using-group_by.md | 0 ...1-19-print-this-page-with-ruby-on-rails.md | 0 ...y-rocks-convince-your-fellow-developers.md | 0 ...ew-in-rails-resource-scaffold-generator.md | 0 ...07-01-23-rails-nested-resource-scaffold.md | 0 ...-updates-wordpress-21-themes-and-social.md | 0 ...ort-an-array-of-objects-by-an-attribute.md | 0 .../2007-02-23-subversion-cheat-sheet-10.md | 0 ...007-02-26-4-unusual-uses-for-subversion.md | 0 ...03-06-subversion-cheat-sheet-update-101.md | 0 ...07-03-07-wordpress-plugin-autoflickr-10.md | 0 ...at-ways-to-use-google-for-your-start-up.md | 0 ...-figures-with-google-adsense-in-10-days.md | 0 ...-21-26-things-you-can-do-with-an-old-pc.md | 0 ...ging-informational-messages-to-your-log.md | 0 ...tive-37-things-you-can-do-on-the-toilet.md | 0 ...5-speedlinking-top-28-startup-resources.md | 0 ...ip-snippet-create-a-comma-seperate-list.md | 0 ...on-how-to-revert-to-a-previous-revision.md | 0 ...-reasons-why-pc-oems-should-offer-linux.md | 0 ...7-04-02-what-do-you-want-for-autoflickr.md | 0 ...2007-04-03-tipsnippet-create-a-rss-feed.md | 0 ...07-04-12-rails-resources-and-permalinks.md | 0 .../2007-04-29-ariejannet-server-move.md | 0 ...ppet-write-like-orwell-with-to_sentence.md | 0 ...007-05-18-feedburner-acquired-by-google.md | 0 ...5-21-merge-request-failed-on-pathtofile.md | 0 .../posts/{ => 2007}/2007-05-28-bat-ter-y.md | 0 ...lling-rmagick-ruby-gem-on-mac-os-x-1049.md | 0 ...007-05-29-slow-connections-with-proftpd.md | 0 ...ebadmin-plugin-and-global-configuration.md | 0 ...ming-up-ubuntu-development-server-guide.md | 0 ...-10-find-and-replace-with-a-mysql-query.md | 0 ...6-10-send-mail-with-a-bash-shell-script.md | 0 ...7-06-10-ultimate-list-of-ruby-resources.md | 0 ...vescaffold-acts_as_taggable_on_steroids.md | 0 ...-12-bash-your-svn-and-trac-installation.md | 0 ...7-06-14-buy-it-now-mac-os-x-105-leopard.md | 0 ...07-06-19-geslaagd-passed-my-final-exams.md | 0 ...ailer-all-mail-comes-from-mailer-daemon.md | 0 ...er-setup-and-deployment-on-ubuntudebian.md | 0 ...cript-solutions-for-professional-coding.md | 0 ...scaffold-acts_as_taggable-auto-complete.md | 0 ...ownloaded-as-a-file-from-your-rails-app.md | 0 .../{ => 2007}/2007-07-03-got-updates.md | 0 ...reate-and-apply-a-patch-with-subversion.md | 0 ...-04-how-to-resolve-subversion-conflicts.md | 0 ...to-write-a-rails-plugin-for-controllers.md | 0 ...07-06-some-dns-problems-with-ariejannet.md | 0 ...07-07-07-clear-dns-cache-on-your-router.md | 0 .../2007-07-16-ariejannet-whats-next.md | 0 .../posts/{ => 2007}/2007-08-01-im-back.md | 0 .../2007-08-20-im-back-in-business.md | 0 ...-kabisa-railsconf-europe-and-ariejannet.md | 0 ...conv-to-convert-utf-8-to-ascii-on-linux.md | 0 ...ple-authentication-plugin-and-generator.md | 0 ...2007-08-27-blueprintcss-rails-generator.md | 0 ...8-31-blueprint-05-rails-plugin-released.md | 0 ...nd-making-sure-something-gets-displayed.md | 0 ...-10-reasons-not-to-use-google-apps-suck.md | 0 .../2007-09-17-railsconf-europe-2007.md | 0 .../2007-09-24-rails-20-new-features.md | 0 ...24-whooop-here-it-is-the-new-ariejannet.md | 0 ...-25-the-glorious-canon-eos-400d-digital.md | 0 .../2007-09-25-wordpress-23-released.md | 0 ...9-26-flash-not-clearing-after-a-request.md | 0 .../2007-10-08-google-increases-storage.md | 0 .../posts/{ => 2007}/2007-10-17-party-time.md | 0 ...-it-number-of-messages-in-postfix-queue.md | 0 ...l-ruby-on-rails-jobs-in-the-netherlands.md | 0 ...set-the-auto-increment-value-of-a-table.md | 0 ...7-12-06-rails-calculated-column-caching.md | 0 ...-jij-mijn-collega-zijn-kabisa-is-hiring.md | 0 ...12-how-to-install-mysql-on-ubuntudebian.md | 0 ...7-natively-on-mac-os-x-leopard-or-tiger.md | 0 ...or-you-merry-christmas-and-a-happy-2008.md | 0 ...rite-a-dvd-video-from-the-linux-console.md | 0 .../2008-01-03-review-parking-london.md | 0 .../{ => 2008}/2008-01-13-kabisa-blog.md | 0 ...2008-01-15-attack-of-the-killer-bunnies.md | 0 ...-19-roles-admins-pretending-to-be-users.md | 0 ...8-01-22-your-help-is-needed-railsjobsnl.md | 0 ...ts-of-the-united-states-of-america-live.md | 0 ...08-02-07-ruby-on-rails-plugin-throttler.md | 0 ...04-09-enabling-trac-email-notifications.md | 0 ...008-04-09-here-we-go-again-wordpress-25.md | 0 ...9-rails-snippet-caching-expensive-calls.md | 0 ...008-04-10-debian-etch-rmagick-loaderror.md | 0 ...15-permanently-redirect-wordpress-pages.md | 0 .../2008-04-23-git-using-the-stash.md | 0 ...ompile-packages-on-debianubuntu-by-hand.md | 0 ...cannot-be-undone-irreversible-migration.md | 0 ...0-the-best-it-books-hand-picked-for-you.md | 0 .../2008-06-06-zoek-jij-n-uitdagende-baan.md | 0 ...08-07-08-ariejannet-link-party-07082008.md | 0 ...9-how-to-digg-proof-your-wordpress-blog.md | 0 ...08-07-10-ariejannet-link-party-07102008.md | 0 .../2008-07-11-photography-heaven.md | 0 ...08-07-17-ariejannet-link-party-07172008.md | 0 ...08-07-21-ariejannet-link-party-07212008.md | 0 ...s-uuid-as-your-activerecord-primary-key.md | 0 ...-14-useless-ruby-gems-for-your-pleasure.md | 0 ...008-08-17-activerecord-read-only-models.md | 0 ...kinny-controllers-and-overweight-models.md | 0 ...09-01-leaving-for-railsconf-europe-2008.md | 0 .../2008-09-02-jruby-with-nick-sieger.md | 0 ...9-02-railsconfeurope-the-first-tutorial.md | 0 .../2008-09-03-jruby-with-thomas-enebo.md | 0 ...cussion-with-dhh-and-rails-core-members.md | 0 ...aseapp-a-quick-start-for-your-rails-app.md | 0 .../2008-11-05-rspecing-with-timenow.md | 70 +- ...008-11-14-sql-ordering-with-null-values.md | 0 ...08-11-27-export-csv-directly-from-mysql.md | 0 ...-google-friendconnect-now-on-ariejannet.md | 0 .../{ => 2008}/2008-12-27-twitterlicious.md | 0 ...-to-start-a-rails-edge-app-the-easy-way.md | 0 .../2009-01-30-pagerank-3-19k-hitsmonth.md | 0 ...2009-02-07-warcraft-armory-010-released.md | 0 .../2009-03-31-may-14th-rubyfest.md | 0 ...ck-screen-of-death-or-is-it-just-faking.md | 0 ...how-to-create-a-dsa-openssl-certificate.md | 0 ...2009-04-23-compacting-a-sqlite3-db-file.md | 0 ...-04-28-available-for-iphone-development.md | 0 ...nd-rubyfest-speaker-geoffrey-grosenbach.md | 0 ...-you-over-the-sound-of-how-awesome-i-am.md | 0 .../{ => 2009}/2009-06-03-ruby-gem-imdb.md | 116 +- .../2009-06-05-install-hpricot-on-ubuntu.md | 0 ...llbacks-like-after_save-or-after_update.md | 0 ...find-all-that-have-no-associated-object.md | 0 ...le-utility-query-imdb-from-your-console.md | 0 ...best-practice-the-git-development-cycle.md | 0 ...by-gem-0-4-0-now-available-at-rubyforge.md | 0 ...009-06-14-speaking-at-rails-underground.md | 0 ...l-rails-migrations-integer-limit-option.md | 0 ...09-09-01-jinput-mac-os-x-64-bit-natives.md | 0 ...case-sensitive-strings-in-your-database.md | 0 .../2009-09-04-git-tag-mini-cheat-sheet.md | 0 ...9-05-git-tag-mini-cheat-sheet-revisited.md | 0 ...009-09-08-codaset-com-github-but-better.md | 0 .../{ => 2009}/2009-10-13-epic-vs-awesome.md | 0 ...erii-32-base-string-encoder-and-decoder.md | 0 ...nable-to-create-temporary-sha1-filename.md | 0 .../2009-10-25-they-are-just-tools-people.md | 0 ...ow-to-create-and-apply-a-patch-with-git.md | 0 .../2009-11-24-epic-textmate-theme.md | 0 ...pic-e-reading-experience-amazone-kindle.md | 0 ...n-the-petition-stop-eu-software-patents.md | 0 ...-order-your-kindle-from-the-netherlands.md | 0 .../2010-03-22-shields-up-rrrack-alert.md | 0 ...010-03-24-ariejannet-now-in-valid-html5.md | 0 ...24-how-a-little-varnish-changed-my-life.md | 0 ...talling-the-nokogiri-ruby-gem-on-debian.md | 0 ...y-another-sinatra-url-shortener-in-ruby.md | 0 ...announcing-firefly-a-ruby-url-shortener.md | 0 ...4-05-detect-browser-web-sockets-support.md | 0 .../2010-04-13-get-ready-for-firefly-03.md | 0 .../2010-04-14-a-new-day-a-new-firefly.md | 0 ...-and-gemset-in-your-bash-prompt-yes-sir.md | 0 .../2010-04-30-firefly-041-released.md | 0 ...ler-passenger-with-rails-235-yes-please.md | 0 .../2010-05-30-upgrading-to-mongoid-beta-6.md | 0 ...fly-043-and-firefly-client-040-released.md | 0 ...own-firefly-url-shortener-in-25-minutes.md | 0 .../2010-06-07-uploading-files-with-curl.md | 0 ...ng-specific-commits-from-another-branch.md | 0 ...y-url-shortener-in-less-than-25-minutes.md | 0 ...ssh-forwarding-on-mac-os-x-snow-leopard.md | 0 .../2010-08-09-rename-a-git-branch.md | 0 ...-08-09-using-multiple-clipboards-in-vim.md | 0 ...08-23-resque-how-to-requeue-failed-jobs.md | 0 ...onvert-wma-to-mp3-using-ffmpeg-and-ruby.md | 0 ...le-sass-to-css-for-deployment-to-heroku.md | 0 ...0-adds-qr-codes-for-your-shortened-urls.md | 0 .../2010-10-11-setup-a-ubuntu-vpn-server.md | 102 +- ...vpn-connection-on-mac-os-x-snow-leopard.md | 0 .../2010-10-26-clear-your-mysql-password.md | 66 +- ...010-11-25-hide-last-login-on-bash-login.md | 0 ...errormessagesfor-disappear-from-rails-3.md | 0 ...public-readable-amazon-s3-bucket-policy.md | 0 .../2010-12-31-now-powered-by-heroku.md | 0 ...sync-your-assets-to-amazon-s3cloudfront.md | 0 ...-hot-firefly-130-url-shortener-released.md | 0 ...y-url-shortener-with-twitter-for-iphone.md | 0 ...-02-11-narf-a-ruby-micro-test-framework.md | 0 ...devise-uploadify-no-flash-session-hacks.md | 0 ...-rake-with-namespaces-and-default-tasks.md | 110 +- .../2011-06-10-vows-and-coffeescript.md | 180 +-- ...6-23-crowd-sourcing-your-bitcoin-mining.md | 174 +-- ...les-were-changed-since-the-last-release.md | 0 ...-slow-disable-spotlight-in-snow-leopard.md | 94 +- ...it-squash-your-latests-commits-into-one.md | 96 +- ...git-log-what-did-i-do-yesterday-exactly.md | 90 +- ...8-git-remove-reset-and-rollback-commits.md | 84 +- ...ngle-file-from-another-commit-or-branch.md | 0 ...s-with-git-capistrano-nginx-and-unicorn.md | 1122 ++++++++--------- ...istrano-and-the-custom-maintenance-page.md | 228 ++-- ...-up-by-tweaking-ruby-garbage-collection.md | 118 +- ...1-09-25-properly-testing-rails-3-scopes.md | 122 +- ...-10-09-testing-rails-3-scopes-revisited.md | 78 +- ...cs-run-your-specs-in-less-than-1-second.md | 478 +++---- ...4-rails-3-customized-exception-handling.md | 200 +-- ...sl-and-non-ssl-with-nginx-unicorn-rails.md | 440 +++---- ...alling-node-js-and-npm-on-ubuntu-debian.md | 0 ...starting-terminal-or-iterm2-on-mac-os-x.md | 0 ...contributing-to-open-source-with-github.md | 174 +-- ...ird-party-rails-application-like-gitlab.md | 150 +-- ...tgresql-8-4-to-postgresql-9-1-on-debian.md | 70 +- ...y-fixing-file-and-directory-permissions.md | 56 +- ...ntracked-files-and-directories-with-git.md | 84 +- ...-open-source-is-a-privilege-not-a-right.md | 96 +- ...-to-0-625s-for-opening-a-rb-file-in-vim.md | 86 +- ...-2gb-of-memory-on-70mb-data-set-the-fix.md | 80 +- ...ing-ruby-rails-and-git-info-in-your-app.md | 110 +- ...4-06-eindhoven-rb-lightning-talk-gitlab.md | 0 ...ating-devise-s-current_user-with-draper.md | 44 +- ...fferent-ruby-with-passenger-3-2-and-rvm.md | 90 +- ...o-downloading-games-from-the-pirate-bay.md | 40 +- ...iablo-3-s-drm-is-the-best-kind-there-is.md | 36 +- ...t-s-causing-all-that-disk-i-o-on-my-mac.md | 48 +- ...ruby-regex-scanning-in-a-case-statement.md | 38 +- ...ek-has-shaped-our-technology-and-future.md | 80 +- .../{ => 2012}/2012-05-24-seo-is-bullshit.md | 122 +- ...-and-replace-in-multiple-files-with-vim.md | 112 +- ...icated-use-a-ip-over-ssh-tunnel-instead.md | 148 +-- ...our-latest-commits-to-a-separate-branch.md | 70 +- ...2012-08-27-getting-started-with-arduino.md | 190 +-- ...-migrations-decimal-precision-and-scale.md | 44 +- .../2012-09-04-git-interactive-revert.md | 124 +- .../2012-10-01-migrate-git-repositories.md | 50 +- .../2012-10-04-a-static-file-server-in-go.md | 40 +- ...rating_sorcery_current_user_with_draper.md | 0 ...1-05-a-call-to-all-ci-service-providers.md | 118 +- .../posts/{ => 2012}/2012-11-22-customac.md | 388 +++--- ...-11-29-binary-debugging-with-git-bisect.md | 286 ++--- ...8-instagram-governments-and-cypherpunks.md | 178 +-- ...8-review-commits-in-your-feature-branch.md | 0 .../2013-03-25-automated-nanoc-deployments.md | 0 .../2013-03-26-i-am-here-for-an-argument.md | 0 .../{ => 2013}/2013-05-21-early-birds.md | 0 .../2013-05-23-divide-and-conquer.md | 0 .../2013-10-31-deploying-with-git-deploy.md | 0 .../2014-04-03-pretty-difficult-privacy.md | 0 .../2014-04-03-to-blog-or-not-to-blog.md | 0 .../2014-04-04-dealing-with-technical-debt.md | 0 ...15-testing-home-with-cucumber-and-aruba.md | 0 .../2014-06-04-gpg-sign-your-git-commits.md | 0 ...29-synchronize-goroutines-in-your-tests.md | 0 ...ls-prevent-accidental-debugging-commits.md | 0 ...-20-why-i-dropped-fish-in-favour-of-zsh.md | 0 .../2015-04-07-testing-with-minitest.md | 0 ...gresql-error-type-hstore-does-not-exist.md | 0 ...5-10-03-a-makefile-for-golang-cli-tools.md | 0 ...-10-12-building-golang-cli-tools-update.md | 0 ...-11-27-rails-generate-model-be-specific.md | 0 ...2-04-el-capitan-safari-new-tab-slow-fix.md | 0 ...an-net-on-a-diet-a-69-percent-reduction.md | 0 ...-and-multi-database-testing-with-travis.md | 0 .../2016-04-24-music-streaming-setup.md | 0 ...6-08-17-squash-git-commits-when-merging.md | 0 .../2017-03-08-bitcoin-mining-anno-2017.md | 0 ...mage-zoom-with-plain-javascript-and-css.md | 0 ...-22-tmux-vim-copy-paste-on-macos-sierra.md | 0 .../2017-12-08-bug-severity-explained.md | 0 ...o-background-a-running-process-over-ssh.md | 0 .../{ => 2020}/2020-02-28-building-a-nas.md | 0 ...020-03-09-the-git-submodule-cheat-sheet.md | 0 ...2020-03-11-drone-hugo-plugin-that-works.md | 0 .../2020-03-17-test-flutter-on-drone-ci.md | 0 ...29-why-i-will-not-repair-your-amplifier.md | 0 ...0-03-repairing-a-xiaomi-roborock-s5-max.md | 0 .../2020-11-12-the-big-diy-nas-update.md | 0 ...ethernet-proxmox-and-ryzentosh-catalina.md | 0 ...023-05-17-base2tone-cave-dark-for-slack.md | 0 ...01-24-prepare-new-hard-disk-for-zfs-nas.md | 0 ...024-01-24-volkswagen-golf-cabrio-update.md | 0 ...-troubleshooting-zfs-online-not-working.md | 0 310 files changed, 3613 insertions(+), 3613 deletions(-) rename content/posts/{ => 2006}/2006-10-09-welcome-to-ariejannet.md (100%) rename content/posts/{ => 2006}/2006-10-10-easily-create-a-favicon-online.md (100%) rename content/posts/{ => 2006}/2006-10-10-generate-a-sqlite-based-rails-app.md (100%) rename content/posts/{ => 2006}/2006-10-10-hi-res-wallpapers-for-you-macbook.md (100%) rename content/posts/{ => 2006}/2006-10-10-top-5-dvds-you-must-have.md (98%) rename content/posts/{ => 2006}/2006-10-13-having-fun-with-spam.md (100%) rename content/posts/{ => 2006}/2006-10-13-migrate-sqlite3-to-mysql-easily.md (100%) rename content/posts/{ => 2006}/2006-10-13-tagging-in-ajax_scaffold.md (100%) rename content/posts/{ => 2006}/2006-10-23-ruby-on-rails-for-php-cakephp.md (100%) rename content/posts/{ => 2006}/2006-10-29-do-your-ads-pay-your-blogging-bills.md (100%) rename content/posts/{ => 2006}/2006-10-30-adsense-resource-inventory.md (100%) rename content/posts/{ => 2006}/2006-10-30-cheat-sheets-look-here.md (100%) rename content/posts/{ => 2006}/2006-10-30-confused-about-css-columns.md (100%) rename content/posts/{ => 2006}/2006-10-30-how-does-your-site-look-on.md (100%) rename content/posts/{ => 2006}/2006-10-31-wordpressmu-dont-allow-new-blogs.md (100%) rename content/posts/{ => 2006}/2006-11-13-cups-426-upgrade-required.md (100%) rename content/posts/{ => 2006}/2006-11-15-ubuntu-610-live-dvd-on-the-apple-macbook.md (100%) rename content/posts/{ => 2006}/2006-11-17-announcing-cse-tool-deploy-you-google-cse-with-ease.md (100%) rename content/posts/{ => 2006}/2006-11-21-cse-tool-110-released.md (100%) rename content/posts/{ => 2006}/2006-11-21-svn-how-to-release-software-properly.md (100%) rename content/posts/{ => 2006}/2006-11-22-google-project-hosting-sourceforge-competitor.md (100%) rename content/posts/{ => 2006}/2006-11-22-svn-how-to-fix-bugs-properly.md (100%) rename content/posts/{ => 2006}/2006-11-22-wordpress-author-comment-highlighting.md (100%) rename content/posts/{ => 2006}/2006-11-24-svn-how-to-structure-your-repository.md (100%) rename content/posts/{ => 2006}/2006-11-25-the-three-corner-stones-of-developerhood.md (100%) rename content/posts/{ => 2006}/2006-11-30-rails-security-check-up.md (100%) rename content/posts/{ => 2006}/2006-12-01-how-to-setup-a-ubuntu-development-server-part-1.md (100%) rename content/posts/{ => 2006}/2006-12-02-how-to-setup-a-ubuntu-development-server-part-2.md (100%) rename content/posts/{ => 2006}/2006-12-03-installing-rails-on-ubuntu-dapper-edgy.md (100%) rename content/posts/{ => 2006}/2006-12-06-install-ruby-mysql-on-mac-os-x-104-tiger.md (100%) rename content/posts/{ => 2006}/2006-12-13-show-the-current-svn-revision-in-your-rails-app.md (100%) rename content/posts/{ => 2006}/2006-12-20-svn-how-often-should-you-commit.md (100%) rename content/posts/{ => 2006}/2006-12-20-svn-merge-a-branch-with-your-trunk.md (100%) rename content/posts/{ => 2006}/2006-12-22-textmaterails-easy-partials-for-better-code.md (97%) rename content/posts/{ => 2007}/2007-01-12-rails-group-results-by-week-using-group_by.md (100%) rename content/posts/{ => 2007}/2007-01-19-print-this-page-with-ruby-on-rails.md (100%) rename content/posts/{ => 2007}/2007-01-19-why-ruby-rocks-convince-your-fellow-developers.md (100%) rename content/posts/{ => 2007}/2007-01-23-new-in-rails-resource-scaffold-generator.md (100%) rename content/posts/{ => 2007}/2007-01-23-rails-nested-resource-scaffold.md (100%) rename content/posts/{ => 2007}/2007-01-23-updates-wordpress-21-themes-and-social.md (100%) rename content/posts/{ => 2007}/2007-01-28-ruby-sort-an-array-of-objects-by-an-attribute.md (100%) rename content/posts/{ => 2007}/2007-02-23-subversion-cheat-sheet-10.md (100%) rename content/posts/{ => 2007}/2007-02-26-4-unusual-uses-for-subversion.md (100%) rename content/posts/{ => 2007}/2007-03-06-subversion-cheat-sheet-update-101.md (100%) rename content/posts/{ => 2007}/2007-03-07-wordpress-plugin-autoflickr-10.md (100%) rename content/posts/{ => 2007}/2007-03-20-8-great-ways-to-use-google-for-your-start-up.md (100%) rename content/posts/{ => 2007}/2007-03-20-how-i-made-6-figures-with-google-adsense-in-10-days.md (100%) rename content/posts/{ => 2007}/2007-03-21-26-things-you-can-do-with-an-old-pc.md (100%) rename content/posts/{ => 2007}/2007-03-22-rails-tip-snippet-logging-informational-messages-to-your-log.md (100%) rename content/posts/{ => 2007}/2007-03-23-be-productive-37-things-you-can-do-on-the-toilet.md (100%) rename content/posts/{ => 2007}/2007-03-25-speedlinking-top-28-startup-resources.md (100%) rename content/posts/{ => 2007}/2007-03-27-rails-tip-snippet-create-a-comma-seperate-list.md (100%) rename content/posts/{ => 2007}/2007-03-27-subversion-how-to-revert-to-a-previous-revision.md (100%) rename content/posts/{ => 2007}/2007-03-29-5-reasons-why-pc-oems-should-offer-linux.md (100%) rename content/posts/{ => 2007}/2007-04-02-what-do-you-want-for-autoflickr.md (100%) rename content/posts/{ => 2007}/2007-04-03-tipsnippet-create-a-rss-feed.md (100%) rename content/posts/{ => 2007}/2007-04-12-rails-resources-and-permalinks.md (100%) rename content/posts/{ => 2007}/2007-04-29-ariejannet-server-move.md (100%) rename content/posts/{ => 2007}/2007-05-09-rails-snippet-write-like-orwell-with-to_sentence.md (100%) rename content/posts/{ => 2007}/2007-05-18-feedburner-acquired-by-google.md (100%) rename content/posts/{ => 2007}/2007-05-21-merge-request-failed-on-pathtofile.md (100%) rename content/posts/{ => 2007}/2007-05-28-bat-ter-y.md (100%) rename content/posts/{ => 2007}/2007-05-29-installing-rmagick-ruby-gem-on-mac-os-x-1049.md (100%) rename content/posts/{ => 2007}/2007-05-29-slow-connections-with-proftpd.md (100%) rename content/posts/{ => 2007}/2007-05-30-trac-webadmin-plugin-and-global-configuration.md (100%) rename content/posts/{ => 2007}/2007-06-07-coming-up-ubuntu-development-server-guide.md (100%) rename content/posts/{ => 2007}/2007-06-10-find-and-replace-with-a-mysql-query.md (100%) rename content/posts/{ => 2007}/2007-06-10-send-mail-with-a-bash-shell-script.md (100%) rename content/posts/{ => 2007}/2007-06-10-ultimate-list-of-ruby-resources.md (100%) rename content/posts/{ => 2007}/2007-06-11-activescaffold-acts_as_taggable_on_steroids.md (100%) rename content/posts/{ => 2007}/2007-06-12-bash-your-svn-and-trac-installation.md (100%) rename content/posts/{ => 2007}/2007-06-14-buy-it-now-mac-os-x-105-leopard.md (100%) rename content/posts/{ => 2007}/2007-06-19-geslaagd-passed-my-final-exams.md (100%) rename content/posts/{ => 2007}/2007-06-20-action-mailer-all-mail-comes-from-mailer-daemon.md (100%) rename content/posts/{ => 2007}/2007-06-20-rails-production-server-setup-and-deployment-on-ubuntudebian.md (100%) rename content/posts/{ => 2007}/2007-06-21-ajax-rules-80-javascript-solutions-for-professional-coding.md (100%) rename content/posts/{ => 2007}/2007-07-01-activescaffold-acts_as_taggable-auto-complete.md (100%) rename content/posts/{ => 2007}/2007-07-02-how-to-force-data-to-be-downloaded-as-a-file-from-your-rails-app.md (100%) rename content/posts/{ => 2007}/2007-07-03-got-updates.md (100%) rename content/posts/{ => 2007}/2007-07-03-how-to-create-and-apply-a-patch-with-subversion.md (100%) rename content/posts/{ => 2007}/2007-07-04-how-to-resolve-subversion-conflicts.md (100%) rename content/posts/{ => 2007}/2007-07-06-how-to-write-a-rails-plugin-for-controllers.md (100%) rename content/posts/{ => 2007}/2007-07-06-some-dns-problems-with-ariejannet.md (100%) rename content/posts/{ => 2007}/2007-07-07-clear-dns-cache-on-your-router.md (100%) rename content/posts/{ => 2007}/2007-07-16-ariejannet-whats-next.md (100%) rename content/posts/{ => 2007}/2007-08-01-im-back.md (100%) rename content/posts/{ => 2007}/2007-08-20-im-back-in-business.md (100%) rename content/posts/{ => 2007}/2007-08-20-kabisa-railsconf-europe-and-ariejannet.md (100%) rename content/posts/{ => 2007}/2007-08-21-using-iconv-to-convert-utf-8-to-ascii-on-linux.md (100%) rename content/posts/{ => 2007}/2007-08-24-super-simple-authentication-plugin-and-generator.md (100%) rename content/posts/{ => 2007}/2007-08-27-blueprintcss-rails-generator.md (100%) rename content/posts/{ => 2007}/2007-08-31-blueprint-05-rails-plugin-released.md (100%) rename content/posts/{ => 2007}/2007-09-01-content_for-yield-and-making-sure-something-gets-displayed.md (100%) rename content/posts/{ => 2007}/2007-09-11-10-reasons-why-microsofts-10-reasons-not-to-use-google-apps-suck.md (100%) rename content/posts/{ => 2007}/2007-09-17-railsconf-europe-2007.md (100%) rename content/posts/{ => 2007}/2007-09-24-rails-20-new-features.md (100%) rename content/posts/{ => 2007}/2007-09-24-whooop-here-it-is-the-new-ariejannet.md (100%) rename content/posts/{ => 2007}/2007-09-25-the-glorious-canon-eos-400d-digital.md (100%) rename content/posts/{ => 2007}/2007-09-25-wordpress-23-released.md (100%) rename content/posts/{ => 2007}/2007-09-26-flash-not-clearing-after-a-request.md (100%) rename content/posts/{ => 2007}/2007-10-08-google-increases-storage.md (100%) rename content/posts/{ => 2007}/2007-10-17-party-time.md (100%) rename content/posts/{ => 2007}/2007-11-15-bash-it-number-of-messages-in-postfix-queue.md (100%) rename content/posts/{ => 2007}/2007-11-27-railsjobsnl-ruby-on-rails-jobs-in-the-netherlands.md (100%) rename content/posts/{ => 2007}/2007-11-30-mysql-reset-the-auto-increment-value-of-a-table.md (100%) rename content/posts/{ => 2007}/2007-12-06-rails-calculated-column-caching.md (100%) rename content/posts/{ => 2007}/2007-12-07-wil-jij-mijn-collega-zijn-kabisa-is-hiring.md (100%) rename content/posts/{ => 2007}/2007-12-12-how-to-install-mysql-on-ubuntudebian.md (100%) rename content/posts/{ => 2007}/2007-12-12-run-internet-explorer-5-55-6-and-7-natively-on-mac-os-x-leopard-or-tiger.md (100%) rename content/posts/{ => 2007}/2007-12-20-for-you-merry-christmas-and-a-happy-2008.md (100%) rename content/posts/{ => 2007}/2007-12-31-write-a-dvd-video-from-the-linux-console.md (100%) rename content/posts/{ => 2008}/2008-01-03-review-parking-london.md (100%) rename content/posts/{ => 2008}/2008-01-13-kabisa-blog.md (100%) rename content/posts/{ => 2008}/2008-01-15-attack-of-the-killer-bunnies.md (100%) rename content/posts/{ => 2008}/2008-01-19-roles-admins-pretending-to-be-users.md (100%) rename content/posts/{ => 2008}/2008-01-22-your-help-is-needed-railsjobsnl.md (100%) rename content/posts/{ => 2008}/2008-01-25-the-presidents-of-the-united-states-of-america-live.md (100%) rename content/posts/{ => 2008}/2008-02-07-ruby-on-rails-plugin-throttler.md (100%) rename content/posts/{ => 2008}/2008-04-09-enabling-trac-email-notifications.md (100%) rename content/posts/{ => 2008}/2008-04-09-here-we-go-again-wordpress-25.md (100%) rename content/posts/{ => 2008}/2008-04-09-rails-snippet-caching-expensive-calls.md (100%) rename content/posts/{ => 2008}/2008-04-10-debian-etch-rmagick-loaderror.md (100%) rename content/posts/{ => 2008}/2008-04-15-permanently-redirect-wordpress-pages.md (100%) rename content/posts/{ => 2008}/2008-04-23-git-using-the-stash.md (100%) rename content/posts/{ => 2008}/2008-05-04-how-to-compile-packages-on-debianubuntu-by-hand.md (100%) rename content/posts/{ => 2008}/2008-05-06-the-migration-that-cannot-be-undone-irreversible-migration.md (100%) rename content/posts/{ => 2008}/2008-05-30-the-best-it-books-hand-picked-for-you.md (100%) rename content/posts/{ => 2008}/2008-06-06-zoek-jij-n-uitdagende-baan.md (100%) rename content/posts/{ => 2008}/2008-07-08-ariejannet-link-party-07082008.md (100%) rename content/posts/{ => 2008}/2008-07-09-how-to-digg-proof-your-wordpress-blog.md (100%) rename content/posts/{ => 2008}/2008-07-10-ariejannet-link-party-07102008.md (100%) rename content/posts/{ => 2008}/2008-07-11-photography-heaven.md (100%) rename content/posts/{ => 2008}/2008-07-17-ariejannet-link-party-07172008.md (100%) rename content/posts/{ => 2008}/2008-07-21-ariejannet-link-party-07212008.md (100%) rename content/posts/{ => 2008}/2008-08-12-ruby-on-rails-uuid-as-your-activerecord-primary-key.md (100%) rename content/posts/{ => 2008}/2008-08-14-useless-ruby-gems-for-your-pleasure.md (100%) rename content/posts/{ => 2008}/2008-08-17-activerecord-read-only-models.md (100%) rename content/posts/{ => 2008}/2008-08-17-skinny-controllers-and-overweight-models.md (100%) rename content/posts/{ => 2008}/2008-09-01-leaving-for-railsconf-europe-2008.md (100%) rename content/posts/{ => 2008}/2008-09-02-jruby-with-nick-sieger.md (100%) rename content/posts/{ => 2008}/2008-09-02-railsconfeurope-the-first-tutorial.md (100%) rename content/posts/{ => 2008}/2008-09-03-jruby-with-thomas-enebo.md (100%) rename content/posts/{ => 2008}/2008-09-03-panel-discussion-with-dhh-and-rails-core-members.md (100%) rename content/posts/{ => 2008}/2008-09-28-baseapp-a-quick-start-for-your-rails-app.md (100%) rename content/posts/{ => 2008}/2008-11-05-rspecing-with-timenow.md (97%) rename content/posts/{ => 2008}/2008-11-14-sql-ordering-with-null-values.md (100%) rename content/posts/{ => 2008}/2008-11-27-export-csv-directly-from-mysql.md (100%) rename content/posts/{ => 2008}/2008-12-03-google-friendconnect-now-on-ariejannet.md (100%) rename content/posts/{ => 2008}/2008-12-27-twitterlicious.md (100%) rename content/posts/{ => 2009}/2009-01-04-how-to-start-a-rails-edge-app-the-easy-way.md (100%) rename content/posts/{ => 2009}/2009-01-30-pagerank-3-19k-hitsmonth.md (100%) rename content/posts/{ => 2009}/2009-02-07-warcraft-armory-010-released.md (100%) rename content/posts/{ => 2009}/2009-03-31-may-14th-rubyfest.md (100%) rename content/posts/{ => 2009}/2009-04-05-macbook-pro-black-screen-of-death-or-is-it-just-faking.md (100%) rename content/posts/{ => 2009}/2009-04-19-how-to-create-a-dsa-openssl-certificate.md (100%) rename content/posts/{ => 2009}/2009-04-23-compacting-a-sqlite3-db-file.md (100%) rename content/posts/{ => 2009}/2009-04-28-available-for-iphone-development.md (100%) rename content/posts/{ => 2009}/2009-05-06-second-rubyfest-speaker-geoffrey-grosenbach.md (100%) rename content/posts/{ => 2009}/2009-05-22-speak-louder-i-cant-hear-you-over-the-sound-of-how-awesome-i-am.md (100%) rename content/posts/{ => 2009}/2009-06-03-ruby-gem-imdb.md (96%) rename content/posts/{ => 2009}/2009-06-05-install-hpricot-on-ubuntu.md (100%) rename content/posts/{ => 2009}/2009-06-07-activerecord-skipping-callbacks-like-after_save-or-after_update.md (100%) rename content/posts/{ => 2009}/2009-06-07-has_one-find-all-that-have-no-associated-object.md (100%) rename content/posts/{ => 2009}/2009-06-07-imdb-0-3-0-now-including-console-utility-query-imdb-from-your-console.md (100%) rename content/posts/{ => 2009}/2009-06-08-best-practice-the-git-development-cycle.md (100%) rename content/posts/{ => 2009}/2009-06-14-imdb-ruby-gem-0-4-0-now-available-at-rubyforge.md (100%) rename content/posts/{ => 2009}/2009-06-14-speaking-at-rails-underground.md (100%) rename content/posts/{ => 2009}/2009-08-20-once-and-for-all-rails-migrations-integer-limit-option.md (100%) rename content/posts/{ => 2009}/2009-09-01-jinput-mac-os-x-64-bit-natives.md (100%) rename content/posts/{ => 2009}/2009-09-03-rails-mysql-case-sensitive-strings-in-your-database.md (100%) rename content/posts/{ => 2009}/2009-09-04-git-tag-mini-cheat-sheet.md (100%) rename content/posts/{ => 2009}/2009-09-05-git-tag-mini-cheat-sheet-revisited.md (100%) rename content/posts/{ => 2009}/2009-09-08-codaset-com-github-but-better.md (100%) rename content/posts/{ => 2009}/2009-10-13-epic-vs-awesome.md (100%) rename content/posts/{ => 2009}/2009-10-13-valerii-32-base-string-encoder-and-decoder.md (100%) rename content/posts/{ => 2009}/2009-10-15-git-problem-error-unable-to-create-temporary-sha1-filename.md (100%) rename content/posts/{ => 2009}/2009-10-25-they-are-just-tools-people.md (100%) rename content/posts/{ => 2009}/2009-10-26-how-to-create-and-apply-a-patch-with-git.md (100%) rename content/posts/{ => 2009}/2009-11-24-epic-textmate-theme.md (100%) rename content/posts/{ => 2010}/2010-01-17-the-epic-e-reading-experience-amazone-kindle.md (100%) rename content/posts/{ => 2010}/2010-01-19-sign-the-petition-stop-eu-software-patents.md (100%) rename content/posts/{ => 2010}/2010-02-02-how-to-order-your-kindle-from-the-netherlands.md (100%) rename content/posts/{ => 2010}/2010-03-22-shields-up-rrrack-alert.md (100%) rename content/posts/{ => 2010}/2010-03-24-ariejannet-now-in-valid-html5.md (100%) rename content/posts/{ => 2010}/2010-03-24-how-a-little-varnish-changed-my-life.md (100%) rename content/posts/{ => 2010}/2010-03-25-installing-the-nokogiri-ruby-gem-on-debian.md (100%) rename content/posts/{ => 2010}/2010-03-28-really-another-sinatra-url-shortener-in-ruby.md (100%) rename content/posts/{ => 2010}/2010-03-29-announcing-firefly-a-ruby-url-shortener.md (100%) rename content/posts/{ => 2010}/2010-04-05-detect-browser-web-sockets-support.md (100%) rename content/posts/{ => 2010}/2010-04-13-get-ready-for-firefly-03.md (100%) rename content/posts/{ => 2010}/2010-04-14-a-new-day-a-new-firefly.md (100%) rename content/posts/{ => 2010}/2010-04-25-ruby-version-and-gemset-in-your-bash-prompt-yes-sir.md (100%) rename content/posts/{ => 2010}/2010-04-30-firefly-041-released.md (100%) rename content/posts/{ => 2010}/2010-05-17-bundler-passenger-with-rails-235-yes-please.md (100%) rename content/posts/{ => 2010}/2010-05-30-upgrading-to-mongoid-beta-6.md (100%) rename content/posts/{ => 2010}/2010-06-06-firefly-043-and-firefly-client-040-released.md (100%) rename content/posts/{ => 2010}/2010-06-06-setup-your-own-firefly-url-shortener-in-25-minutes.md (100%) rename content/posts/{ => 2010}/2010-06-07-uploading-files-with-curl.md (100%) rename content/posts/{ => 2010}/2010-06-10-cherry-picking-specific-commits-from-another-branch.md (100%) rename content/posts/{ => 2010}/2010-07-12-screencast-firefly-url-shortener-in-less-than-25-minutes.md (100%) rename content/posts/{ => 2010}/2010-07-29-how-to-enable-ssh-forwarding-on-mac-os-x-snow-leopard.md (100%) rename content/posts/{ => 2010}/2010-08-09-rename-a-git-branch.md (100%) rename content/posts/{ => 2010}/2010-08-09-using-multiple-clipboards-in-vim.md (100%) rename content/posts/{ => 2010}/2010-08-23-resque-how-to-requeue-failed-jobs.md (100%) rename content/posts/{ => 2010}/2010-09-11-mass-convert-wma-to-mp3-using-ffmpeg-and-ruby.md (100%) rename content/posts/{ => 2010}/2010-09-28-precompile-sass-to-css-for-deployment-to-heroku.md (100%) rename content/posts/{ => 2010}/2010-10-02-firefly-110-adds-qr-codes-for-your-shortened-urls.md (100%) rename content/posts/{ => 2010}/2010-10-11-setup-a-ubuntu-vpn-server.md (96%) rename content/posts/{ => 2010}/2010-10-12-setup-a-pptp-vpn-connection-on-mac-os-x-snow-leopard.md (100%) rename content/posts/{ => 2010}/2010-10-26-clear-your-mysql-password.md (97%) rename content/posts/{ => 2010}/2010-11-25-hide-last-login-on-bash-login.md (100%) rename content/posts/{ => 2010}/2010-12-15-why-did-errormessagesfor-disappear-from-rails-3.md (100%) rename content/posts/{ => 2010}/2010-12-24-public-readable-amazon-s3-bucket-policy.md (100%) rename content/posts/{ => 2010}/2010-12-31-now-powered-by-heroku.md (100%) rename content/posts/{ => 2011}/2011-01-01-rake-task-to-sync-your-assets-to-amazon-s3cloudfront.md (100%) rename content/posts/{ => 2011}/2011-02-01-hot-firefly-130-url-shortener-released.md (100%) rename content/posts/{ => 2011}/2011-02-07-using-your-firefly-url-shortener-with-twitter-for-iphone.md (100%) rename content/posts/{ => 2011}/2011-02-11-narf-a-ruby-micro-test-framework.md (100%) rename content/posts/{ => 2011}/2011-03-27-rails-3-devise-uploadify-no-flash-session-hacks.md (100%) rename content/posts/{ => 2011}/2011-04-04-rake-with-namespaces-and-default-tasks.md (96%) rename content/posts/{ => 2011}/2011-06-10-vows-and-coffeescript.md (96%) rename content/posts/{ => 2011}/2011-06-23-crowd-sourcing-your-bitcoin-mining.md (98%) rename content/posts/{ => 2011}/2011-06-24-git-what-files-were-changed-since-the-last-release.md (100%) rename content/posts/{ => 2011}/2011-06-27-your-mac-slow-disable-spotlight-in-snow-leopard.md (97%) rename content/posts/{ => 2011}/2011-07-05-git-squash-your-latests-commits-into-one.md (97%) rename content/posts/{ => 2011}/2011-08-24-git-log-what-did-i-do-yesterday-exactly.md (97%) rename content/posts/{ => 2011}/2011-09-08-git-remove-reset-and-rollback-commits.md (97%) rename content/posts/{ => 2011}/2011-09-13-git-checkout-a-single-file-from-another-commit-or-branch.md (100%) rename content/posts/{ => 2011}/2011-09-14-lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn.md (96%) rename content/posts/{ => 2011}/2011-09-19-capistrano-and-the-custom-maintenance-page.md (97%) rename content/posts/{ => 2011}/2011-09-24-rspec-speed-up-by-tweaking-ruby-garbage-collection.md (97%) rename content/posts/{ => 2011}/2011-09-25-properly-testing-rails-3-scopes.md (97%) rename content/posts/{ => 2011}/2011-10-09-testing-rails-3-scopes-revisited.md (97%) rename content/posts/{ => 2011}/2011-10-13-fast-specs-run-your-specs-in-less-than-1-second.md (97%) rename content/posts/{ => 2011}/2011-10-14-rails-3-customized-exception-handling.md (96%) rename content/posts/{ => 2011}/2011-10-22-automatically-switch-between-ssl-and-non-ssl-with-nginx-unicorn-rails.md (97%) rename content/posts/{ => 2011}/2011-10-24-installing-node-js-and-npm-on-ubuntu-debian.md (100%) rename content/posts/{ => 2011}/2011-11-08-fixing-a-slow-starting-terminal-or-iterm2-on-mac-os-x.md (100%) rename content/posts/{ => 2011}/2011-11-09-contributing-to-open-source-with-github.md (97%) rename content/posts/{ => 2011}/2011-11-18-deploying-a-third-party-rails-application-like-gitlab.md (97%) rename content/posts/{ => 2011}/2011-11-22-upgrade-postgresql-8-4-to-postgresql-9-1-on-debian.md (96%) rename content/posts/{ => 2011}/2011-12-13-recursively-fixing-file-and-directory-permissions.md (97%) rename content/posts/{ => 2012}/2012-01-10-removing-untracked-files-and-directories-with-git.md (98%) rename content/posts/{ => 2012}/2012-03-20-open-source-is-a-privilege-not-a-right.md (98%) rename content/posts/{ => 2012}/2012-03-21-from-11-34s-to-0-625s-for-opening-a-rb-file-in-vim.md (98%) rename content/posts/{ => 2012}/2012-03-21-redis-using-2gb-of-memory-on-70mb-data-set-the-fix.md (98%) rename content/posts/{ => 2012}/2012-04-02-showing-ruby-rails-and-git-info-in-your-app.md (96%) rename content/posts/{ => 2012}/2012-04-06-eindhoven-rb-lightning-talk-gitlab.md (100%) rename content/posts/{ => 2012}/2012-04-14-decorating-devise-s-current_user-with-draper.md (97%) rename content/posts/{ => 2012}/2012-05-11-running-a-different-ruby-with-passenger-3-2-and-rvm.md (98%) rename content/posts/{ => 2012}/2012-05-19-what-happened-to-downloading-games-from-the-pirate-bay.md (98%) rename content/posts/{ => 2012}/2012-05-20-why-diablo-3-s-drm-is-the-best-kind-there-is.md (99%) rename content/posts/{ => 2012}/2012-05-21-what-s-causing-all-that-disk-i-o-on-my-mac.md (99%) rename content/posts/{ => 2012}/2012-05-22-ruby-regex-scanning-in-a-case-statement.md (96%) rename content/posts/{ => 2012}/2012-05-23-how-star-trek-has-shaped-our-technology-and-future.md (98%) rename content/posts/{ => 2012}/2012-05-24-seo-is-bullshit.md (97%) rename content/posts/{ => 2012}/2012-06-18-search-and-replace-in-multiple-files-with-vim.md (97%) rename content/posts/{ => 2012}/2012-07-11-vpn-too-complicated-use-a-ip-over-ssh-tunnel-instead.md (97%) rename content/posts/{ => 2012}/2012-08-14-move-your-latest-commits-to-a-separate-branch.md (96%) rename content/posts/{ => 2012}/2012-08-27-getting-started-with-arduino.md (98%) rename content/posts/{ => 2012}/2012-08-28-rails-migrations-decimal-precision-and-scale.md (98%) rename content/posts/{ => 2012}/2012-09-04-git-interactive-revert.md (96%) rename content/posts/{ => 2012}/2012-10-01-migrate-git-repositories.md (96%) rename content/posts/{ => 2012}/2012-10-04-a-static-file-server-in-go.md (97%) rename content/posts/{ => 2012}/2012-11-02-decorating_sorcery_current_user_with_draper.md (100%) rename content/posts/{ => 2012}/2012-11-05-a-call-to-all-ci-service-providers.md (98%) rename content/posts/{ => 2012}/2012-11-22-customac.md (98%) rename content/posts/{ => 2012}/2012-11-29-binary-debugging-with-git-bisect.md (97%) rename content/posts/{ => 2012}/2012-12-18-instagram-governments-and-cypherpunks.md (98%) rename content/posts/{ => 2013}/2013-03-08-review-commits-in-your-feature-branch.md (100%) rename content/posts/{ => 2013}/2013-03-25-automated-nanoc-deployments.md (100%) rename content/posts/{ => 2013}/2013-03-26-i-am-here-for-an-argument.md (100%) rename content/posts/{ => 2013}/2013-05-21-early-birds.md (100%) rename content/posts/{ => 2013}/2013-05-23-divide-and-conquer.md (100%) rename content/posts/{ => 2013}/2013-10-31-deploying-with-git-deploy.md (100%) rename content/posts/{ => 2014}/2014-04-03-pretty-difficult-privacy.md (100%) rename content/posts/{ => 2014}/2014-04-03-to-blog-or-not-to-blog.md (100%) rename content/posts/{ => 2014}/2014-04-04-dealing-with-technical-debt.md (100%) rename content/posts/{ => 2014}/2014-04-15-testing-home-with-cucumber-and-aruba.md (100%) rename content/posts/{ => 2014}/2014-06-04-gpg-sign-your-git-commits.md (100%) rename content/posts/{ => 2014}/2014-08-29-synchronize-goroutines-in-your-tests.md (100%) rename content/posts/{ => 2014}/2014-10-15-rails-prevent-accidental-debugging-commits.md (100%) rename content/posts/{ => 2014}/2014-11-20-why-i-dropped-fish-in-favour-of-zsh.md (100%) rename content/posts/{ => 2015}/2015-04-07-testing-with-minitest.md (100%) rename content/posts/{ => 2015}/2015-08-05-postgresql-error-type-hstore-does-not-exist.md (100%) rename content/posts/{ => 2015}/2015-10-03-a-makefile-for-golang-cli-tools.md (100%) rename content/posts/{ => 2015}/2015-10-12-building-golang-cli-tools-update.md (100%) rename content/posts/{ => 2015}/2015-11-27-rails-generate-model-be-specific.md (100%) rename content/posts/{ => 2015}/2015-12-04-el-capitan-safari-new-tab-slow-fix.md (100%) rename content/posts/{ => 2016}/2016-01-06-putting-ariejan-net-on-a-diet-a-69-percent-reduction.md (100%) rename content/posts/{ => 2016}/2016-04-15-hanami-and-multi-database-testing-with-travis.md (100%) rename content/posts/{ => 2016}/2016-04-24-music-streaming-setup.md (100%) rename content/posts/{ => 2016}/2016-08-17-squash-git-commits-when-merging.md (100%) rename content/posts/{ => 2017}/2017-03-08-bitcoin-mining-anno-2017.md (100%) rename content/posts/{ => 2017}/2017-03-20-image-zoom-with-plain-javascript-and-css.md (100%) rename content/posts/{ => 2017}/2017-03-22-tmux-vim-copy-paste-on-macos-sierra.md (100%) rename content/posts/{ => 2017}/2017-12-08-bug-severity-explained.md (100%) rename content/posts/{ => 2019}/2019-08-28-how-to-background-a-running-process-over-ssh.md (100%) rename content/posts/{ => 2020}/2020-02-28-building-a-nas.md (100%) rename content/posts/{ => 2020}/2020-03-09-the-git-submodule-cheat-sheet.md (100%) rename content/posts/{ => 2020}/2020-03-11-drone-hugo-plugin-that-works.md (100%) rename content/posts/{ => 2020}/2020-03-17-test-flutter-on-drone-ci.md (100%) rename content/posts/{ => 2020}/2020-03-29-why-i-will-not-repair-your-amplifier.md (100%) rename content/posts/{ => 2020}/2020-10-03-repairing-a-xiaomi-roborock-s5-max.md (100%) rename content/posts/{ => 2020}/2020-11-12-the-big-diy-nas-update.md (100%) rename content/posts/{ => 2020}/2020-11-18-10gb-ethernet-proxmox-and-ryzentosh-catalina.md (100%) rename content/posts/{ => 2023}/2023-05-17-base2tone-cave-dark-for-slack.md (100%) rename content/posts/{ => 2024}/2024-01-24-prepare-new-hard-disk-for-zfs-nas.md (100%) rename content/posts/{ => 2024}/2024-01-24-volkswagen-golf-cabrio-update.md (100%) rename content/posts/{ => 2024}/2024-01-27-troubleshooting-zfs-online-not-working.md (100%) diff --git a/content/posts/2006-10-09-welcome-to-ariejannet.md b/content/posts/2006/2006-10-09-welcome-to-ariejannet.md similarity index 100% rename from content/posts/2006-10-09-welcome-to-ariejannet.md rename to content/posts/2006/2006-10-09-welcome-to-ariejannet.md diff --git a/content/posts/2006-10-10-easily-create-a-favicon-online.md b/content/posts/2006/2006-10-10-easily-create-a-favicon-online.md similarity index 100% rename from content/posts/2006-10-10-easily-create-a-favicon-online.md rename to content/posts/2006/2006-10-10-easily-create-a-favicon-online.md diff --git a/content/posts/2006-10-10-generate-a-sqlite-based-rails-app.md b/content/posts/2006/2006-10-10-generate-a-sqlite-based-rails-app.md similarity index 100% rename from content/posts/2006-10-10-generate-a-sqlite-based-rails-app.md rename to content/posts/2006/2006-10-10-generate-a-sqlite-based-rails-app.md diff --git a/content/posts/2006-10-10-hi-res-wallpapers-for-you-macbook.md b/content/posts/2006/2006-10-10-hi-res-wallpapers-for-you-macbook.md similarity index 100% rename from content/posts/2006-10-10-hi-res-wallpapers-for-you-macbook.md rename to content/posts/2006/2006-10-10-hi-res-wallpapers-for-you-macbook.md diff --git a/content/posts/2006-10-10-top-5-dvds-you-must-have.md b/content/posts/2006/2006-10-10-top-5-dvds-you-must-have.md similarity index 98% rename from content/posts/2006-10-10-top-5-dvds-you-must-have.md rename to content/posts/2006/2006-10-10-top-5-dvds-you-must-have.md index 30dd8e3..c0efdeb 100644 --- a/content/posts/2006-10-10-top-5-dvds-you-must-have.md +++ b/content/posts/2006/2006-10-10-top-5-dvds-you-must-have.md @@ -1,52 +1,52 @@ -+++ -date = "2006-10-10" -title = "Top 5 DVDs you must have" -tags = ["General", "Everything", "Blog", "Lists", "Movies", "DVD", "Coding"] -slug = "top-5-dvds-you-must-have" -description = "Top 5 DVDs I love watching - 2006 edition." -+++ -Everybody at this point in time at least owns one or more DVD - Digital Versatile Disk - Videos. Some people try to collect as many DVD's as possible, others just buy the ones they like (or can afford). - -I'm not sure how many DVD's I have at this time, but there are quite a few DVD's that you just have to have in your collection. - -If you feel wronged because your favourite movie is not listed, feel free to add a comment stating your favourites. (Oh, let me know why it's such a great movie too!) - - -

5. Gladiator

- -GladiatorGladiator, by Ridley Scott, is tells the story off a Roman general who became a slave and then a gladiator. It sounds pretty boring when you put it like that, but Scott really makes it into a very gripping movie. - -Gladiator is more than a few man in shorts fighting in a big bowl of sand. You should really check this one out and add it to your collection. - -

4. The Lord of the Rings Trilogy

- -Lord of the RingsWell, The Lord of the Rings is not really a trilogy since it is one big story. Still, this movie is great. - -LOTR, by Peter Jackson, attracts old and young alike. It features humour, heroism, love, massive battles between good and evil and everything else needed to make a successful movie. - -Many complain that the Fellowship (part 1) does not have much action in it and that Return of the king (part 2) is just one big fat ending. Well, that's correct. In my opinion you should watch the three movies in sequence all at once. That will give you the full sensation the way Jackson intended it. - -Because this movie appeals to a very broad audience, it's placed at position 4. - -

3. Pulp Ficton

- -Pulp FictionThe combining of several story lines into one movie with a lot of violence by Quentin Tarantino. The result is Pulp Fiction. - -Every story line has it's own characters and Tarantino was able to get a lot of big names attached to this film including Bruce Willis, John Travolta, Samuel L. Jackson and Uma Thurman. - -This movie is not just entertainment, it's art. If you don't have it, you should probably get is a.s.a.p. - -

2. Star Wars (all six of 'em)

- -Star WarsStar Wars is the work of George Lucas. George has done many innovative things during the creation of his Star Wars movies. Not only was he the first to introduce (and claim the rights to) merchandising, he has also brought special effects to a new level. Of course, I don't have to remind you that George Lucas is also the genius behind the THX sound system. - -If I have to tell you what Star Wars is about, you should not be allowed to have a DVD collection at all. - -

1. The Godfather Trilogy

- -The GodfatherI think everybody knows the Godfather. Directed by Francis Ford Coppola, this epic trilogy gives us an inside look in the Corleone family. - -Part one is really the best movie of all three. It's based on the original novel by Mario Puzo. However, parts two and three really complement the whole story and that's what makes this such a great trilogy. - -There are some very nice Trilogy DVD Boxes available. If you say you like movies, you cannot be taken seriously unless you have this trilogy in your collection. - ++++ +date = "2006-10-10" +title = "Top 5 DVDs you must have" +tags = ["General", "Everything", "Blog", "Lists", "Movies", "DVD", "Coding"] +slug = "top-5-dvds-you-must-have" +description = "Top 5 DVDs I love watching - 2006 edition." ++++ +Everybody at this point in time at least owns one or more DVD - Digital Versatile Disk - Videos. Some people try to collect as many DVD's as possible, others just buy the ones they like (or can afford). + +I'm not sure how many DVD's I have at this time, but there are quite a few DVD's that you just have to have in your collection. + +If you feel wronged because your favourite movie is not listed, feel free to add a comment stating your favourites. (Oh, let me know why it's such a great movie too!) + + +

5. Gladiator

+ +GladiatorGladiator, by Ridley Scott, is tells the story off a Roman general who became a slave and then a gladiator. It sounds pretty boring when you put it like that, but Scott really makes it into a very gripping movie. + +Gladiator is more than a few man in shorts fighting in a big bowl of sand. You should really check this one out and add it to your collection. + +

4. The Lord of the Rings Trilogy

+ +Lord of the RingsWell, The Lord of the Rings is not really a trilogy since it is one big story. Still, this movie is great. + +LOTR, by Peter Jackson, attracts old and young alike. It features humour, heroism, love, massive battles between good and evil and everything else needed to make a successful movie. + +Many complain that the Fellowship (part 1) does not have much action in it and that Return of the king (part 2) is just one big fat ending. Well, that's correct. In my opinion you should watch the three movies in sequence all at once. That will give you the full sensation the way Jackson intended it. + +Because this movie appeals to a very broad audience, it's placed at position 4. + +

3. Pulp Ficton

+ +Pulp FictionThe combining of several story lines into one movie with a lot of violence by Quentin Tarantino. The result is Pulp Fiction. + +Every story line has it's own characters and Tarantino was able to get a lot of big names attached to this film including Bruce Willis, John Travolta, Samuel L. Jackson and Uma Thurman. + +This movie is not just entertainment, it's art. If you don't have it, you should probably get is a.s.a.p. + +

2. Star Wars (all six of 'em)

+ +Star WarsStar Wars is the work of George Lucas. George has done many innovative things during the creation of his Star Wars movies. Not only was he the first to introduce (and claim the rights to) merchandising, he has also brought special effects to a new level. Of course, I don't have to remind you that George Lucas is also the genius behind the THX sound system. + +If I have to tell you what Star Wars is about, you should not be allowed to have a DVD collection at all. + +

1. The Godfather Trilogy

+ +The GodfatherI think everybody knows the Godfather. Directed by Francis Ford Coppola, this epic trilogy gives us an inside look in the Corleone family. + +Part one is really the best movie of all three. It's based on the original novel by Mario Puzo. However, parts two and three really complement the whole story and that's what makes this such a great trilogy. + +There are some very nice Trilogy DVD Boxes available. If you say you like movies, you cannot be taken seriously unless you have this trilogy in your collection. + diff --git a/content/posts/2006-10-13-having-fun-with-spam.md b/content/posts/2006/2006-10-13-having-fun-with-spam.md similarity index 100% rename from content/posts/2006-10-13-having-fun-with-spam.md rename to content/posts/2006/2006-10-13-having-fun-with-spam.md diff --git a/content/posts/2006-10-13-migrate-sqlite3-to-mysql-easily.md b/content/posts/2006/2006-10-13-migrate-sqlite3-to-mysql-easily.md similarity index 100% rename from content/posts/2006-10-13-migrate-sqlite3-to-mysql-easily.md rename to content/posts/2006/2006-10-13-migrate-sqlite3-to-mysql-easily.md diff --git a/content/posts/2006-10-13-tagging-in-ajax_scaffold.md b/content/posts/2006/2006-10-13-tagging-in-ajax_scaffold.md similarity index 100% rename from content/posts/2006-10-13-tagging-in-ajax_scaffold.md rename to content/posts/2006/2006-10-13-tagging-in-ajax_scaffold.md diff --git a/content/posts/2006-10-23-ruby-on-rails-for-php-cakephp.md b/content/posts/2006/2006-10-23-ruby-on-rails-for-php-cakephp.md similarity index 100% rename from content/posts/2006-10-23-ruby-on-rails-for-php-cakephp.md rename to content/posts/2006/2006-10-23-ruby-on-rails-for-php-cakephp.md diff --git a/content/posts/2006-10-29-do-your-ads-pay-your-blogging-bills.md b/content/posts/2006/2006-10-29-do-your-ads-pay-your-blogging-bills.md similarity index 100% rename from content/posts/2006-10-29-do-your-ads-pay-your-blogging-bills.md rename to content/posts/2006/2006-10-29-do-your-ads-pay-your-blogging-bills.md diff --git a/content/posts/2006-10-30-adsense-resource-inventory.md b/content/posts/2006/2006-10-30-adsense-resource-inventory.md similarity index 100% rename from content/posts/2006-10-30-adsense-resource-inventory.md rename to content/posts/2006/2006-10-30-adsense-resource-inventory.md diff --git a/content/posts/2006-10-30-cheat-sheets-look-here.md b/content/posts/2006/2006-10-30-cheat-sheets-look-here.md similarity index 100% rename from content/posts/2006-10-30-cheat-sheets-look-here.md rename to content/posts/2006/2006-10-30-cheat-sheets-look-here.md diff --git a/content/posts/2006-10-30-confused-about-css-columns.md b/content/posts/2006/2006-10-30-confused-about-css-columns.md similarity index 100% rename from content/posts/2006-10-30-confused-about-css-columns.md rename to content/posts/2006/2006-10-30-confused-about-css-columns.md diff --git a/content/posts/2006-10-30-how-does-your-site-look-on.md b/content/posts/2006/2006-10-30-how-does-your-site-look-on.md similarity index 100% rename from content/posts/2006-10-30-how-does-your-site-look-on.md rename to content/posts/2006/2006-10-30-how-does-your-site-look-on.md diff --git a/content/posts/2006-10-31-wordpressmu-dont-allow-new-blogs.md b/content/posts/2006/2006-10-31-wordpressmu-dont-allow-new-blogs.md similarity index 100% rename from content/posts/2006-10-31-wordpressmu-dont-allow-new-blogs.md rename to content/posts/2006/2006-10-31-wordpressmu-dont-allow-new-blogs.md diff --git a/content/posts/2006-11-13-cups-426-upgrade-required.md b/content/posts/2006/2006-11-13-cups-426-upgrade-required.md similarity index 100% rename from content/posts/2006-11-13-cups-426-upgrade-required.md rename to content/posts/2006/2006-11-13-cups-426-upgrade-required.md diff --git a/content/posts/2006-11-15-ubuntu-610-live-dvd-on-the-apple-macbook.md b/content/posts/2006/2006-11-15-ubuntu-610-live-dvd-on-the-apple-macbook.md similarity index 100% rename from content/posts/2006-11-15-ubuntu-610-live-dvd-on-the-apple-macbook.md rename to content/posts/2006/2006-11-15-ubuntu-610-live-dvd-on-the-apple-macbook.md diff --git a/content/posts/2006-11-17-announcing-cse-tool-deploy-you-google-cse-with-ease.md b/content/posts/2006/2006-11-17-announcing-cse-tool-deploy-you-google-cse-with-ease.md similarity index 100% rename from content/posts/2006-11-17-announcing-cse-tool-deploy-you-google-cse-with-ease.md rename to content/posts/2006/2006-11-17-announcing-cse-tool-deploy-you-google-cse-with-ease.md diff --git a/content/posts/2006-11-21-cse-tool-110-released.md b/content/posts/2006/2006-11-21-cse-tool-110-released.md similarity index 100% rename from content/posts/2006-11-21-cse-tool-110-released.md rename to content/posts/2006/2006-11-21-cse-tool-110-released.md diff --git a/content/posts/2006-11-21-svn-how-to-release-software-properly.md b/content/posts/2006/2006-11-21-svn-how-to-release-software-properly.md similarity index 100% rename from content/posts/2006-11-21-svn-how-to-release-software-properly.md rename to content/posts/2006/2006-11-21-svn-how-to-release-software-properly.md diff --git a/content/posts/2006-11-22-google-project-hosting-sourceforge-competitor.md b/content/posts/2006/2006-11-22-google-project-hosting-sourceforge-competitor.md similarity index 100% rename from content/posts/2006-11-22-google-project-hosting-sourceforge-competitor.md rename to content/posts/2006/2006-11-22-google-project-hosting-sourceforge-competitor.md diff --git a/content/posts/2006-11-22-svn-how-to-fix-bugs-properly.md b/content/posts/2006/2006-11-22-svn-how-to-fix-bugs-properly.md similarity index 100% rename from content/posts/2006-11-22-svn-how-to-fix-bugs-properly.md rename to content/posts/2006/2006-11-22-svn-how-to-fix-bugs-properly.md diff --git a/content/posts/2006-11-22-wordpress-author-comment-highlighting.md b/content/posts/2006/2006-11-22-wordpress-author-comment-highlighting.md similarity index 100% rename from content/posts/2006-11-22-wordpress-author-comment-highlighting.md rename to content/posts/2006/2006-11-22-wordpress-author-comment-highlighting.md diff --git a/content/posts/2006-11-24-svn-how-to-structure-your-repository.md b/content/posts/2006/2006-11-24-svn-how-to-structure-your-repository.md similarity index 100% rename from content/posts/2006-11-24-svn-how-to-structure-your-repository.md rename to content/posts/2006/2006-11-24-svn-how-to-structure-your-repository.md diff --git a/content/posts/2006-11-25-the-three-corner-stones-of-developerhood.md b/content/posts/2006/2006-11-25-the-three-corner-stones-of-developerhood.md similarity index 100% rename from content/posts/2006-11-25-the-three-corner-stones-of-developerhood.md rename to content/posts/2006/2006-11-25-the-three-corner-stones-of-developerhood.md diff --git a/content/posts/2006-11-30-rails-security-check-up.md b/content/posts/2006/2006-11-30-rails-security-check-up.md similarity index 100% rename from content/posts/2006-11-30-rails-security-check-up.md rename to content/posts/2006/2006-11-30-rails-security-check-up.md diff --git a/content/posts/2006-12-01-how-to-setup-a-ubuntu-development-server-part-1.md b/content/posts/2006/2006-12-01-how-to-setup-a-ubuntu-development-server-part-1.md similarity index 100% rename from content/posts/2006-12-01-how-to-setup-a-ubuntu-development-server-part-1.md rename to content/posts/2006/2006-12-01-how-to-setup-a-ubuntu-development-server-part-1.md diff --git a/content/posts/2006-12-02-how-to-setup-a-ubuntu-development-server-part-2.md b/content/posts/2006/2006-12-02-how-to-setup-a-ubuntu-development-server-part-2.md similarity index 100% rename from content/posts/2006-12-02-how-to-setup-a-ubuntu-development-server-part-2.md rename to content/posts/2006/2006-12-02-how-to-setup-a-ubuntu-development-server-part-2.md diff --git a/content/posts/2006-12-03-installing-rails-on-ubuntu-dapper-edgy.md b/content/posts/2006/2006-12-03-installing-rails-on-ubuntu-dapper-edgy.md similarity index 100% rename from content/posts/2006-12-03-installing-rails-on-ubuntu-dapper-edgy.md rename to content/posts/2006/2006-12-03-installing-rails-on-ubuntu-dapper-edgy.md diff --git a/content/posts/2006-12-06-install-ruby-mysql-on-mac-os-x-104-tiger.md b/content/posts/2006/2006-12-06-install-ruby-mysql-on-mac-os-x-104-tiger.md similarity index 100% rename from content/posts/2006-12-06-install-ruby-mysql-on-mac-os-x-104-tiger.md rename to content/posts/2006/2006-12-06-install-ruby-mysql-on-mac-os-x-104-tiger.md diff --git a/content/posts/2006-12-13-show-the-current-svn-revision-in-your-rails-app.md b/content/posts/2006/2006-12-13-show-the-current-svn-revision-in-your-rails-app.md similarity index 100% rename from content/posts/2006-12-13-show-the-current-svn-revision-in-your-rails-app.md rename to content/posts/2006/2006-12-13-show-the-current-svn-revision-in-your-rails-app.md diff --git a/content/posts/2006-12-20-svn-how-often-should-you-commit.md b/content/posts/2006/2006-12-20-svn-how-often-should-you-commit.md similarity index 100% rename from content/posts/2006-12-20-svn-how-often-should-you-commit.md rename to content/posts/2006/2006-12-20-svn-how-often-should-you-commit.md diff --git a/content/posts/2006-12-20-svn-merge-a-branch-with-your-trunk.md b/content/posts/2006/2006-12-20-svn-merge-a-branch-with-your-trunk.md similarity index 100% rename from content/posts/2006-12-20-svn-merge-a-branch-with-your-trunk.md rename to content/posts/2006/2006-12-20-svn-merge-a-branch-with-your-trunk.md diff --git a/content/posts/2006-12-22-textmaterails-easy-partials-for-better-code.md b/content/posts/2006/2006-12-22-textmaterails-easy-partials-for-better-code.md similarity index 97% rename from content/posts/2006-12-22-textmaterails-easy-partials-for-better-code.md rename to content/posts/2006/2006-12-22-textmaterails-easy-partials-for-better-code.md index 2757f06..a76ad76 100644 --- a/content/posts/2006-12-22-textmaterails-easy-partials-for-better-code.md +++ b/content/posts/2006/2006-12-22-textmaterails-easy-partials-for-better-code.md @@ -67,7 +67,7 @@ As you may see, this is chaos. It's not easy to read and you can't easily change This is where TextMate does it's magic. Here's a before snaphot: -before.png +before.png Now, select the part between the if and else statements. This is where a normal profile is shown. Next, use TextMate: SHIFT-CTRL-H. You'll get a pop-up asking you how you'd like to name the partial. In this case I choose 'profile'. diff --git a/content/posts/2007-01-12-rails-group-results-by-week-using-group_by.md b/content/posts/2007/2007-01-12-rails-group-results-by-week-using-group_by.md similarity index 100% rename from content/posts/2007-01-12-rails-group-results-by-week-using-group_by.md rename to content/posts/2007/2007-01-12-rails-group-results-by-week-using-group_by.md diff --git a/content/posts/2007-01-19-print-this-page-with-ruby-on-rails.md b/content/posts/2007/2007-01-19-print-this-page-with-ruby-on-rails.md similarity index 100% rename from content/posts/2007-01-19-print-this-page-with-ruby-on-rails.md rename to content/posts/2007/2007-01-19-print-this-page-with-ruby-on-rails.md diff --git a/content/posts/2007-01-19-why-ruby-rocks-convince-your-fellow-developers.md b/content/posts/2007/2007-01-19-why-ruby-rocks-convince-your-fellow-developers.md similarity index 100% rename from content/posts/2007-01-19-why-ruby-rocks-convince-your-fellow-developers.md rename to content/posts/2007/2007-01-19-why-ruby-rocks-convince-your-fellow-developers.md diff --git a/content/posts/2007-01-23-new-in-rails-resource-scaffold-generator.md b/content/posts/2007/2007-01-23-new-in-rails-resource-scaffold-generator.md similarity index 100% rename from content/posts/2007-01-23-new-in-rails-resource-scaffold-generator.md rename to content/posts/2007/2007-01-23-new-in-rails-resource-scaffold-generator.md diff --git a/content/posts/2007-01-23-rails-nested-resource-scaffold.md b/content/posts/2007/2007-01-23-rails-nested-resource-scaffold.md similarity index 100% rename from content/posts/2007-01-23-rails-nested-resource-scaffold.md rename to content/posts/2007/2007-01-23-rails-nested-resource-scaffold.md diff --git a/content/posts/2007-01-23-updates-wordpress-21-themes-and-social.md b/content/posts/2007/2007-01-23-updates-wordpress-21-themes-and-social.md similarity index 100% rename from content/posts/2007-01-23-updates-wordpress-21-themes-and-social.md rename to content/posts/2007/2007-01-23-updates-wordpress-21-themes-and-social.md diff --git a/content/posts/2007-01-28-ruby-sort-an-array-of-objects-by-an-attribute.md b/content/posts/2007/2007-01-28-ruby-sort-an-array-of-objects-by-an-attribute.md similarity index 100% rename from content/posts/2007-01-28-ruby-sort-an-array-of-objects-by-an-attribute.md rename to content/posts/2007/2007-01-28-ruby-sort-an-array-of-objects-by-an-attribute.md diff --git a/content/posts/2007-02-23-subversion-cheat-sheet-10.md b/content/posts/2007/2007-02-23-subversion-cheat-sheet-10.md similarity index 100% rename from content/posts/2007-02-23-subversion-cheat-sheet-10.md rename to content/posts/2007/2007-02-23-subversion-cheat-sheet-10.md diff --git a/content/posts/2007-02-26-4-unusual-uses-for-subversion.md b/content/posts/2007/2007-02-26-4-unusual-uses-for-subversion.md similarity index 100% rename from content/posts/2007-02-26-4-unusual-uses-for-subversion.md rename to content/posts/2007/2007-02-26-4-unusual-uses-for-subversion.md diff --git a/content/posts/2007-03-06-subversion-cheat-sheet-update-101.md b/content/posts/2007/2007-03-06-subversion-cheat-sheet-update-101.md similarity index 100% rename from content/posts/2007-03-06-subversion-cheat-sheet-update-101.md rename to content/posts/2007/2007-03-06-subversion-cheat-sheet-update-101.md diff --git a/content/posts/2007-03-07-wordpress-plugin-autoflickr-10.md b/content/posts/2007/2007-03-07-wordpress-plugin-autoflickr-10.md similarity index 100% rename from content/posts/2007-03-07-wordpress-plugin-autoflickr-10.md rename to content/posts/2007/2007-03-07-wordpress-plugin-autoflickr-10.md diff --git a/content/posts/2007-03-20-8-great-ways-to-use-google-for-your-start-up.md b/content/posts/2007/2007-03-20-8-great-ways-to-use-google-for-your-start-up.md similarity index 100% rename from content/posts/2007-03-20-8-great-ways-to-use-google-for-your-start-up.md rename to content/posts/2007/2007-03-20-8-great-ways-to-use-google-for-your-start-up.md diff --git a/content/posts/2007-03-20-how-i-made-6-figures-with-google-adsense-in-10-days.md b/content/posts/2007/2007-03-20-how-i-made-6-figures-with-google-adsense-in-10-days.md similarity index 100% rename from content/posts/2007-03-20-how-i-made-6-figures-with-google-adsense-in-10-days.md rename to content/posts/2007/2007-03-20-how-i-made-6-figures-with-google-adsense-in-10-days.md diff --git a/content/posts/2007-03-21-26-things-you-can-do-with-an-old-pc.md b/content/posts/2007/2007-03-21-26-things-you-can-do-with-an-old-pc.md similarity index 100% rename from content/posts/2007-03-21-26-things-you-can-do-with-an-old-pc.md rename to content/posts/2007/2007-03-21-26-things-you-can-do-with-an-old-pc.md diff --git a/content/posts/2007-03-22-rails-tip-snippet-logging-informational-messages-to-your-log.md b/content/posts/2007/2007-03-22-rails-tip-snippet-logging-informational-messages-to-your-log.md similarity index 100% rename from content/posts/2007-03-22-rails-tip-snippet-logging-informational-messages-to-your-log.md rename to content/posts/2007/2007-03-22-rails-tip-snippet-logging-informational-messages-to-your-log.md diff --git a/content/posts/2007-03-23-be-productive-37-things-you-can-do-on-the-toilet.md b/content/posts/2007/2007-03-23-be-productive-37-things-you-can-do-on-the-toilet.md similarity index 100% rename from content/posts/2007-03-23-be-productive-37-things-you-can-do-on-the-toilet.md rename to content/posts/2007/2007-03-23-be-productive-37-things-you-can-do-on-the-toilet.md diff --git a/content/posts/2007-03-25-speedlinking-top-28-startup-resources.md b/content/posts/2007/2007-03-25-speedlinking-top-28-startup-resources.md similarity index 100% rename from content/posts/2007-03-25-speedlinking-top-28-startup-resources.md rename to content/posts/2007/2007-03-25-speedlinking-top-28-startup-resources.md diff --git a/content/posts/2007-03-27-rails-tip-snippet-create-a-comma-seperate-list.md b/content/posts/2007/2007-03-27-rails-tip-snippet-create-a-comma-seperate-list.md similarity index 100% rename from content/posts/2007-03-27-rails-tip-snippet-create-a-comma-seperate-list.md rename to content/posts/2007/2007-03-27-rails-tip-snippet-create-a-comma-seperate-list.md diff --git a/content/posts/2007-03-27-subversion-how-to-revert-to-a-previous-revision.md b/content/posts/2007/2007-03-27-subversion-how-to-revert-to-a-previous-revision.md similarity index 100% rename from content/posts/2007-03-27-subversion-how-to-revert-to-a-previous-revision.md rename to content/posts/2007/2007-03-27-subversion-how-to-revert-to-a-previous-revision.md diff --git a/content/posts/2007-03-29-5-reasons-why-pc-oems-should-offer-linux.md b/content/posts/2007/2007-03-29-5-reasons-why-pc-oems-should-offer-linux.md similarity index 100% rename from content/posts/2007-03-29-5-reasons-why-pc-oems-should-offer-linux.md rename to content/posts/2007/2007-03-29-5-reasons-why-pc-oems-should-offer-linux.md diff --git a/content/posts/2007-04-02-what-do-you-want-for-autoflickr.md b/content/posts/2007/2007-04-02-what-do-you-want-for-autoflickr.md similarity index 100% rename from content/posts/2007-04-02-what-do-you-want-for-autoflickr.md rename to content/posts/2007/2007-04-02-what-do-you-want-for-autoflickr.md diff --git a/content/posts/2007-04-03-tipsnippet-create-a-rss-feed.md b/content/posts/2007/2007-04-03-tipsnippet-create-a-rss-feed.md similarity index 100% rename from content/posts/2007-04-03-tipsnippet-create-a-rss-feed.md rename to content/posts/2007/2007-04-03-tipsnippet-create-a-rss-feed.md diff --git a/content/posts/2007-04-12-rails-resources-and-permalinks.md b/content/posts/2007/2007-04-12-rails-resources-and-permalinks.md similarity index 100% rename from content/posts/2007-04-12-rails-resources-and-permalinks.md rename to content/posts/2007/2007-04-12-rails-resources-and-permalinks.md diff --git a/content/posts/2007-04-29-ariejannet-server-move.md b/content/posts/2007/2007-04-29-ariejannet-server-move.md similarity index 100% rename from content/posts/2007-04-29-ariejannet-server-move.md rename to content/posts/2007/2007-04-29-ariejannet-server-move.md diff --git a/content/posts/2007-05-09-rails-snippet-write-like-orwell-with-to_sentence.md b/content/posts/2007/2007-05-09-rails-snippet-write-like-orwell-with-to_sentence.md similarity index 100% rename from content/posts/2007-05-09-rails-snippet-write-like-orwell-with-to_sentence.md rename to content/posts/2007/2007-05-09-rails-snippet-write-like-orwell-with-to_sentence.md diff --git a/content/posts/2007-05-18-feedburner-acquired-by-google.md b/content/posts/2007/2007-05-18-feedburner-acquired-by-google.md similarity index 100% rename from content/posts/2007-05-18-feedburner-acquired-by-google.md rename to content/posts/2007/2007-05-18-feedburner-acquired-by-google.md diff --git a/content/posts/2007-05-21-merge-request-failed-on-pathtofile.md b/content/posts/2007/2007-05-21-merge-request-failed-on-pathtofile.md similarity index 100% rename from content/posts/2007-05-21-merge-request-failed-on-pathtofile.md rename to content/posts/2007/2007-05-21-merge-request-failed-on-pathtofile.md diff --git a/content/posts/2007-05-28-bat-ter-y.md b/content/posts/2007/2007-05-28-bat-ter-y.md similarity index 100% rename from content/posts/2007-05-28-bat-ter-y.md rename to content/posts/2007/2007-05-28-bat-ter-y.md diff --git a/content/posts/2007-05-29-installing-rmagick-ruby-gem-on-mac-os-x-1049.md b/content/posts/2007/2007-05-29-installing-rmagick-ruby-gem-on-mac-os-x-1049.md similarity index 100% rename from content/posts/2007-05-29-installing-rmagick-ruby-gem-on-mac-os-x-1049.md rename to content/posts/2007/2007-05-29-installing-rmagick-ruby-gem-on-mac-os-x-1049.md diff --git a/content/posts/2007-05-29-slow-connections-with-proftpd.md b/content/posts/2007/2007-05-29-slow-connections-with-proftpd.md similarity index 100% rename from content/posts/2007-05-29-slow-connections-with-proftpd.md rename to content/posts/2007/2007-05-29-slow-connections-with-proftpd.md diff --git a/content/posts/2007-05-30-trac-webadmin-plugin-and-global-configuration.md b/content/posts/2007/2007-05-30-trac-webadmin-plugin-and-global-configuration.md similarity index 100% rename from content/posts/2007-05-30-trac-webadmin-plugin-and-global-configuration.md rename to content/posts/2007/2007-05-30-trac-webadmin-plugin-and-global-configuration.md diff --git a/content/posts/2007-06-07-coming-up-ubuntu-development-server-guide.md b/content/posts/2007/2007-06-07-coming-up-ubuntu-development-server-guide.md similarity index 100% rename from content/posts/2007-06-07-coming-up-ubuntu-development-server-guide.md rename to content/posts/2007/2007-06-07-coming-up-ubuntu-development-server-guide.md diff --git a/content/posts/2007-06-10-find-and-replace-with-a-mysql-query.md b/content/posts/2007/2007-06-10-find-and-replace-with-a-mysql-query.md similarity index 100% rename from content/posts/2007-06-10-find-and-replace-with-a-mysql-query.md rename to content/posts/2007/2007-06-10-find-and-replace-with-a-mysql-query.md diff --git a/content/posts/2007-06-10-send-mail-with-a-bash-shell-script.md b/content/posts/2007/2007-06-10-send-mail-with-a-bash-shell-script.md similarity index 100% rename from content/posts/2007-06-10-send-mail-with-a-bash-shell-script.md rename to content/posts/2007/2007-06-10-send-mail-with-a-bash-shell-script.md diff --git a/content/posts/2007-06-10-ultimate-list-of-ruby-resources.md b/content/posts/2007/2007-06-10-ultimate-list-of-ruby-resources.md similarity index 100% rename from content/posts/2007-06-10-ultimate-list-of-ruby-resources.md rename to content/posts/2007/2007-06-10-ultimate-list-of-ruby-resources.md diff --git a/content/posts/2007-06-11-activescaffold-acts_as_taggable_on_steroids.md b/content/posts/2007/2007-06-11-activescaffold-acts_as_taggable_on_steroids.md similarity index 100% rename from content/posts/2007-06-11-activescaffold-acts_as_taggable_on_steroids.md rename to content/posts/2007/2007-06-11-activescaffold-acts_as_taggable_on_steroids.md diff --git a/content/posts/2007-06-12-bash-your-svn-and-trac-installation.md b/content/posts/2007/2007-06-12-bash-your-svn-and-trac-installation.md similarity index 100% rename from content/posts/2007-06-12-bash-your-svn-and-trac-installation.md rename to content/posts/2007/2007-06-12-bash-your-svn-and-trac-installation.md diff --git a/content/posts/2007-06-14-buy-it-now-mac-os-x-105-leopard.md b/content/posts/2007/2007-06-14-buy-it-now-mac-os-x-105-leopard.md similarity index 100% rename from content/posts/2007-06-14-buy-it-now-mac-os-x-105-leopard.md rename to content/posts/2007/2007-06-14-buy-it-now-mac-os-x-105-leopard.md diff --git a/content/posts/2007-06-19-geslaagd-passed-my-final-exams.md b/content/posts/2007/2007-06-19-geslaagd-passed-my-final-exams.md similarity index 100% rename from content/posts/2007-06-19-geslaagd-passed-my-final-exams.md rename to content/posts/2007/2007-06-19-geslaagd-passed-my-final-exams.md diff --git a/content/posts/2007-06-20-action-mailer-all-mail-comes-from-mailer-daemon.md b/content/posts/2007/2007-06-20-action-mailer-all-mail-comes-from-mailer-daemon.md similarity index 100% rename from content/posts/2007-06-20-action-mailer-all-mail-comes-from-mailer-daemon.md rename to content/posts/2007/2007-06-20-action-mailer-all-mail-comes-from-mailer-daemon.md diff --git a/content/posts/2007-06-20-rails-production-server-setup-and-deployment-on-ubuntudebian.md b/content/posts/2007/2007-06-20-rails-production-server-setup-and-deployment-on-ubuntudebian.md similarity index 100% rename from content/posts/2007-06-20-rails-production-server-setup-and-deployment-on-ubuntudebian.md rename to content/posts/2007/2007-06-20-rails-production-server-setup-and-deployment-on-ubuntudebian.md diff --git a/content/posts/2007-06-21-ajax-rules-80-javascript-solutions-for-professional-coding.md b/content/posts/2007/2007-06-21-ajax-rules-80-javascript-solutions-for-professional-coding.md similarity index 100% rename from content/posts/2007-06-21-ajax-rules-80-javascript-solutions-for-professional-coding.md rename to content/posts/2007/2007-06-21-ajax-rules-80-javascript-solutions-for-professional-coding.md diff --git a/content/posts/2007-07-01-activescaffold-acts_as_taggable-auto-complete.md b/content/posts/2007/2007-07-01-activescaffold-acts_as_taggable-auto-complete.md similarity index 100% rename from content/posts/2007-07-01-activescaffold-acts_as_taggable-auto-complete.md rename to content/posts/2007/2007-07-01-activescaffold-acts_as_taggable-auto-complete.md diff --git a/content/posts/2007-07-02-how-to-force-data-to-be-downloaded-as-a-file-from-your-rails-app.md b/content/posts/2007/2007-07-02-how-to-force-data-to-be-downloaded-as-a-file-from-your-rails-app.md similarity index 100% rename from content/posts/2007-07-02-how-to-force-data-to-be-downloaded-as-a-file-from-your-rails-app.md rename to content/posts/2007/2007-07-02-how-to-force-data-to-be-downloaded-as-a-file-from-your-rails-app.md diff --git a/content/posts/2007-07-03-got-updates.md b/content/posts/2007/2007-07-03-got-updates.md similarity index 100% rename from content/posts/2007-07-03-got-updates.md rename to content/posts/2007/2007-07-03-got-updates.md diff --git a/content/posts/2007-07-03-how-to-create-and-apply-a-patch-with-subversion.md b/content/posts/2007/2007-07-03-how-to-create-and-apply-a-patch-with-subversion.md similarity index 100% rename from content/posts/2007-07-03-how-to-create-and-apply-a-patch-with-subversion.md rename to content/posts/2007/2007-07-03-how-to-create-and-apply-a-patch-with-subversion.md diff --git a/content/posts/2007-07-04-how-to-resolve-subversion-conflicts.md b/content/posts/2007/2007-07-04-how-to-resolve-subversion-conflicts.md similarity index 100% rename from content/posts/2007-07-04-how-to-resolve-subversion-conflicts.md rename to content/posts/2007/2007-07-04-how-to-resolve-subversion-conflicts.md diff --git a/content/posts/2007-07-06-how-to-write-a-rails-plugin-for-controllers.md b/content/posts/2007/2007-07-06-how-to-write-a-rails-plugin-for-controllers.md similarity index 100% rename from content/posts/2007-07-06-how-to-write-a-rails-plugin-for-controllers.md rename to content/posts/2007/2007-07-06-how-to-write-a-rails-plugin-for-controllers.md diff --git a/content/posts/2007-07-06-some-dns-problems-with-ariejannet.md b/content/posts/2007/2007-07-06-some-dns-problems-with-ariejannet.md similarity index 100% rename from content/posts/2007-07-06-some-dns-problems-with-ariejannet.md rename to content/posts/2007/2007-07-06-some-dns-problems-with-ariejannet.md diff --git a/content/posts/2007-07-07-clear-dns-cache-on-your-router.md b/content/posts/2007/2007-07-07-clear-dns-cache-on-your-router.md similarity index 100% rename from content/posts/2007-07-07-clear-dns-cache-on-your-router.md rename to content/posts/2007/2007-07-07-clear-dns-cache-on-your-router.md diff --git a/content/posts/2007-07-16-ariejannet-whats-next.md b/content/posts/2007/2007-07-16-ariejannet-whats-next.md similarity index 100% rename from content/posts/2007-07-16-ariejannet-whats-next.md rename to content/posts/2007/2007-07-16-ariejannet-whats-next.md diff --git a/content/posts/2007-08-01-im-back.md b/content/posts/2007/2007-08-01-im-back.md similarity index 100% rename from content/posts/2007-08-01-im-back.md rename to content/posts/2007/2007-08-01-im-back.md diff --git a/content/posts/2007-08-20-im-back-in-business.md b/content/posts/2007/2007-08-20-im-back-in-business.md similarity index 100% rename from content/posts/2007-08-20-im-back-in-business.md rename to content/posts/2007/2007-08-20-im-back-in-business.md diff --git a/content/posts/2007-08-20-kabisa-railsconf-europe-and-ariejannet.md b/content/posts/2007/2007-08-20-kabisa-railsconf-europe-and-ariejannet.md similarity index 100% rename from content/posts/2007-08-20-kabisa-railsconf-europe-and-ariejannet.md rename to content/posts/2007/2007-08-20-kabisa-railsconf-europe-and-ariejannet.md diff --git a/content/posts/2007-08-21-using-iconv-to-convert-utf-8-to-ascii-on-linux.md b/content/posts/2007/2007-08-21-using-iconv-to-convert-utf-8-to-ascii-on-linux.md similarity index 100% rename from content/posts/2007-08-21-using-iconv-to-convert-utf-8-to-ascii-on-linux.md rename to content/posts/2007/2007-08-21-using-iconv-to-convert-utf-8-to-ascii-on-linux.md diff --git a/content/posts/2007-08-24-super-simple-authentication-plugin-and-generator.md b/content/posts/2007/2007-08-24-super-simple-authentication-plugin-and-generator.md similarity index 100% rename from content/posts/2007-08-24-super-simple-authentication-plugin-and-generator.md rename to content/posts/2007/2007-08-24-super-simple-authentication-plugin-and-generator.md diff --git a/content/posts/2007-08-27-blueprintcss-rails-generator.md b/content/posts/2007/2007-08-27-blueprintcss-rails-generator.md similarity index 100% rename from content/posts/2007-08-27-blueprintcss-rails-generator.md rename to content/posts/2007/2007-08-27-blueprintcss-rails-generator.md diff --git a/content/posts/2007-08-31-blueprint-05-rails-plugin-released.md b/content/posts/2007/2007-08-31-blueprint-05-rails-plugin-released.md similarity index 100% rename from content/posts/2007-08-31-blueprint-05-rails-plugin-released.md rename to content/posts/2007/2007-08-31-blueprint-05-rails-plugin-released.md diff --git a/content/posts/2007-09-01-content_for-yield-and-making-sure-something-gets-displayed.md b/content/posts/2007/2007-09-01-content_for-yield-and-making-sure-something-gets-displayed.md similarity index 100% rename from content/posts/2007-09-01-content_for-yield-and-making-sure-something-gets-displayed.md rename to content/posts/2007/2007-09-01-content_for-yield-and-making-sure-something-gets-displayed.md diff --git a/content/posts/2007-09-11-10-reasons-why-microsofts-10-reasons-not-to-use-google-apps-suck.md b/content/posts/2007/2007-09-11-10-reasons-why-microsofts-10-reasons-not-to-use-google-apps-suck.md similarity index 100% rename from content/posts/2007-09-11-10-reasons-why-microsofts-10-reasons-not-to-use-google-apps-suck.md rename to content/posts/2007/2007-09-11-10-reasons-why-microsofts-10-reasons-not-to-use-google-apps-suck.md diff --git a/content/posts/2007-09-17-railsconf-europe-2007.md b/content/posts/2007/2007-09-17-railsconf-europe-2007.md similarity index 100% rename from content/posts/2007-09-17-railsconf-europe-2007.md rename to content/posts/2007/2007-09-17-railsconf-europe-2007.md diff --git a/content/posts/2007-09-24-rails-20-new-features.md b/content/posts/2007/2007-09-24-rails-20-new-features.md similarity index 100% rename from content/posts/2007-09-24-rails-20-new-features.md rename to content/posts/2007/2007-09-24-rails-20-new-features.md diff --git a/content/posts/2007-09-24-whooop-here-it-is-the-new-ariejannet.md b/content/posts/2007/2007-09-24-whooop-here-it-is-the-new-ariejannet.md similarity index 100% rename from content/posts/2007-09-24-whooop-here-it-is-the-new-ariejannet.md rename to content/posts/2007/2007-09-24-whooop-here-it-is-the-new-ariejannet.md diff --git a/content/posts/2007-09-25-the-glorious-canon-eos-400d-digital.md b/content/posts/2007/2007-09-25-the-glorious-canon-eos-400d-digital.md similarity index 100% rename from content/posts/2007-09-25-the-glorious-canon-eos-400d-digital.md rename to content/posts/2007/2007-09-25-the-glorious-canon-eos-400d-digital.md diff --git a/content/posts/2007-09-25-wordpress-23-released.md b/content/posts/2007/2007-09-25-wordpress-23-released.md similarity index 100% rename from content/posts/2007-09-25-wordpress-23-released.md rename to content/posts/2007/2007-09-25-wordpress-23-released.md diff --git a/content/posts/2007-09-26-flash-not-clearing-after-a-request.md b/content/posts/2007/2007-09-26-flash-not-clearing-after-a-request.md similarity index 100% rename from content/posts/2007-09-26-flash-not-clearing-after-a-request.md rename to content/posts/2007/2007-09-26-flash-not-clearing-after-a-request.md diff --git a/content/posts/2007-10-08-google-increases-storage.md b/content/posts/2007/2007-10-08-google-increases-storage.md similarity index 100% rename from content/posts/2007-10-08-google-increases-storage.md rename to content/posts/2007/2007-10-08-google-increases-storage.md diff --git a/content/posts/2007-10-17-party-time.md b/content/posts/2007/2007-10-17-party-time.md similarity index 100% rename from content/posts/2007-10-17-party-time.md rename to content/posts/2007/2007-10-17-party-time.md diff --git a/content/posts/2007-11-15-bash-it-number-of-messages-in-postfix-queue.md b/content/posts/2007/2007-11-15-bash-it-number-of-messages-in-postfix-queue.md similarity index 100% rename from content/posts/2007-11-15-bash-it-number-of-messages-in-postfix-queue.md rename to content/posts/2007/2007-11-15-bash-it-number-of-messages-in-postfix-queue.md diff --git a/content/posts/2007-11-27-railsjobsnl-ruby-on-rails-jobs-in-the-netherlands.md b/content/posts/2007/2007-11-27-railsjobsnl-ruby-on-rails-jobs-in-the-netherlands.md similarity index 100% rename from content/posts/2007-11-27-railsjobsnl-ruby-on-rails-jobs-in-the-netherlands.md rename to content/posts/2007/2007-11-27-railsjobsnl-ruby-on-rails-jobs-in-the-netherlands.md diff --git a/content/posts/2007-11-30-mysql-reset-the-auto-increment-value-of-a-table.md b/content/posts/2007/2007-11-30-mysql-reset-the-auto-increment-value-of-a-table.md similarity index 100% rename from content/posts/2007-11-30-mysql-reset-the-auto-increment-value-of-a-table.md rename to content/posts/2007/2007-11-30-mysql-reset-the-auto-increment-value-of-a-table.md diff --git a/content/posts/2007-12-06-rails-calculated-column-caching.md b/content/posts/2007/2007-12-06-rails-calculated-column-caching.md similarity index 100% rename from content/posts/2007-12-06-rails-calculated-column-caching.md rename to content/posts/2007/2007-12-06-rails-calculated-column-caching.md diff --git a/content/posts/2007-12-07-wil-jij-mijn-collega-zijn-kabisa-is-hiring.md b/content/posts/2007/2007-12-07-wil-jij-mijn-collega-zijn-kabisa-is-hiring.md similarity index 100% rename from content/posts/2007-12-07-wil-jij-mijn-collega-zijn-kabisa-is-hiring.md rename to content/posts/2007/2007-12-07-wil-jij-mijn-collega-zijn-kabisa-is-hiring.md diff --git a/content/posts/2007-12-12-how-to-install-mysql-on-ubuntudebian.md b/content/posts/2007/2007-12-12-how-to-install-mysql-on-ubuntudebian.md similarity index 100% rename from content/posts/2007-12-12-how-to-install-mysql-on-ubuntudebian.md rename to content/posts/2007/2007-12-12-how-to-install-mysql-on-ubuntudebian.md diff --git a/content/posts/2007-12-12-run-internet-explorer-5-55-6-and-7-natively-on-mac-os-x-leopard-or-tiger.md b/content/posts/2007/2007-12-12-run-internet-explorer-5-55-6-and-7-natively-on-mac-os-x-leopard-or-tiger.md similarity index 100% rename from content/posts/2007-12-12-run-internet-explorer-5-55-6-and-7-natively-on-mac-os-x-leopard-or-tiger.md rename to content/posts/2007/2007-12-12-run-internet-explorer-5-55-6-and-7-natively-on-mac-os-x-leopard-or-tiger.md diff --git a/content/posts/2007-12-20-for-you-merry-christmas-and-a-happy-2008.md b/content/posts/2007/2007-12-20-for-you-merry-christmas-and-a-happy-2008.md similarity index 100% rename from content/posts/2007-12-20-for-you-merry-christmas-and-a-happy-2008.md rename to content/posts/2007/2007-12-20-for-you-merry-christmas-and-a-happy-2008.md diff --git a/content/posts/2007-12-31-write-a-dvd-video-from-the-linux-console.md b/content/posts/2007/2007-12-31-write-a-dvd-video-from-the-linux-console.md similarity index 100% rename from content/posts/2007-12-31-write-a-dvd-video-from-the-linux-console.md rename to content/posts/2007/2007-12-31-write-a-dvd-video-from-the-linux-console.md diff --git a/content/posts/2008-01-03-review-parking-london.md b/content/posts/2008/2008-01-03-review-parking-london.md similarity index 100% rename from content/posts/2008-01-03-review-parking-london.md rename to content/posts/2008/2008-01-03-review-parking-london.md diff --git a/content/posts/2008-01-13-kabisa-blog.md b/content/posts/2008/2008-01-13-kabisa-blog.md similarity index 100% rename from content/posts/2008-01-13-kabisa-blog.md rename to content/posts/2008/2008-01-13-kabisa-blog.md diff --git a/content/posts/2008-01-15-attack-of-the-killer-bunnies.md b/content/posts/2008/2008-01-15-attack-of-the-killer-bunnies.md similarity index 100% rename from content/posts/2008-01-15-attack-of-the-killer-bunnies.md rename to content/posts/2008/2008-01-15-attack-of-the-killer-bunnies.md diff --git a/content/posts/2008-01-19-roles-admins-pretending-to-be-users.md b/content/posts/2008/2008-01-19-roles-admins-pretending-to-be-users.md similarity index 100% rename from content/posts/2008-01-19-roles-admins-pretending-to-be-users.md rename to content/posts/2008/2008-01-19-roles-admins-pretending-to-be-users.md diff --git a/content/posts/2008-01-22-your-help-is-needed-railsjobsnl.md b/content/posts/2008/2008-01-22-your-help-is-needed-railsjobsnl.md similarity index 100% rename from content/posts/2008-01-22-your-help-is-needed-railsjobsnl.md rename to content/posts/2008/2008-01-22-your-help-is-needed-railsjobsnl.md diff --git a/content/posts/2008-01-25-the-presidents-of-the-united-states-of-america-live.md b/content/posts/2008/2008-01-25-the-presidents-of-the-united-states-of-america-live.md similarity index 100% rename from content/posts/2008-01-25-the-presidents-of-the-united-states-of-america-live.md rename to content/posts/2008/2008-01-25-the-presidents-of-the-united-states-of-america-live.md diff --git a/content/posts/2008-02-07-ruby-on-rails-plugin-throttler.md b/content/posts/2008/2008-02-07-ruby-on-rails-plugin-throttler.md similarity index 100% rename from content/posts/2008-02-07-ruby-on-rails-plugin-throttler.md rename to content/posts/2008/2008-02-07-ruby-on-rails-plugin-throttler.md diff --git a/content/posts/2008-04-09-enabling-trac-email-notifications.md b/content/posts/2008/2008-04-09-enabling-trac-email-notifications.md similarity index 100% rename from content/posts/2008-04-09-enabling-trac-email-notifications.md rename to content/posts/2008/2008-04-09-enabling-trac-email-notifications.md diff --git a/content/posts/2008-04-09-here-we-go-again-wordpress-25.md b/content/posts/2008/2008-04-09-here-we-go-again-wordpress-25.md similarity index 100% rename from content/posts/2008-04-09-here-we-go-again-wordpress-25.md rename to content/posts/2008/2008-04-09-here-we-go-again-wordpress-25.md diff --git a/content/posts/2008-04-09-rails-snippet-caching-expensive-calls.md b/content/posts/2008/2008-04-09-rails-snippet-caching-expensive-calls.md similarity index 100% rename from content/posts/2008-04-09-rails-snippet-caching-expensive-calls.md rename to content/posts/2008/2008-04-09-rails-snippet-caching-expensive-calls.md diff --git a/content/posts/2008-04-10-debian-etch-rmagick-loaderror.md b/content/posts/2008/2008-04-10-debian-etch-rmagick-loaderror.md similarity index 100% rename from content/posts/2008-04-10-debian-etch-rmagick-loaderror.md rename to content/posts/2008/2008-04-10-debian-etch-rmagick-loaderror.md diff --git a/content/posts/2008-04-15-permanently-redirect-wordpress-pages.md b/content/posts/2008/2008-04-15-permanently-redirect-wordpress-pages.md similarity index 100% rename from content/posts/2008-04-15-permanently-redirect-wordpress-pages.md rename to content/posts/2008/2008-04-15-permanently-redirect-wordpress-pages.md diff --git a/content/posts/2008-04-23-git-using-the-stash.md b/content/posts/2008/2008-04-23-git-using-the-stash.md similarity index 100% rename from content/posts/2008-04-23-git-using-the-stash.md rename to content/posts/2008/2008-04-23-git-using-the-stash.md diff --git a/content/posts/2008-05-04-how-to-compile-packages-on-debianubuntu-by-hand.md b/content/posts/2008/2008-05-04-how-to-compile-packages-on-debianubuntu-by-hand.md similarity index 100% rename from content/posts/2008-05-04-how-to-compile-packages-on-debianubuntu-by-hand.md rename to content/posts/2008/2008-05-04-how-to-compile-packages-on-debianubuntu-by-hand.md diff --git a/content/posts/2008-05-06-the-migration-that-cannot-be-undone-irreversible-migration.md b/content/posts/2008/2008-05-06-the-migration-that-cannot-be-undone-irreversible-migration.md similarity index 100% rename from content/posts/2008-05-06-the-migration-that-cannot-be-undone-irreversible-migration.md rename to content/posts/2008/2008-05-06-the-migration-that-cannot-be-undone-irreversible-migration.md diff --git a/content/posts/2008-05-30-the-best-it-books-hand-picked-for-you.md b/content/posts/2008/2008-05-30-the-best-it-books-hand-picked-for-you.md similarity index 100% rename from content/posts/2008-05-30-the-best-it-books-hand-picked-for-you.md rename to content/posts/2008/2008-05-30-the-best-it-books-hand-picked-for-you.md diff --git a/content/posts/2008-06-06-zoek-jij-n-uitdagende-baan.md b/content/posts/2008/2008-06-06-zoek-jij-n-uitdagende-baan.md similarity index 100% rename from content/posts/2008-06-06-zoek-jij-n-uitdagende-baan.md rename to content/posts/2008/2008-06-06-zoek-jij-n-uitdagende-baan.md diff --git a/content/posts/2008-07-08-ariejannet-link-party-07082008.md b/content/posts/2008/2008-07-08-ariejannet-link-party-07082008.md similarity index 100% rename from content/posts/2008-07-08-ariejannet-link-party-07082008.md rename to content/posts/2008/2008-07-08-ariejannet-link-party-07082008.md diff --git a/content/posts/2008-07-09-how-to-digg-proof-your-wordpress-blog.md b/content/posts/2008/2008-07-09-how-to-digg-proof-your-wordpress-blog.md similarity index 100% rename from content/posts/2008-07-09-how-to-digg-proof-your-wordpress-blog.md rename to content/posts/2008/2008-07-09-how-to-digg-proof-your-wordpress-blog.md diff --git a/content/posts/2008-07-10-ariejannet-link-party-07102008.md b/content/posts/2008/2008-07-10-ariejannet-link-party-07102008.md similarity index 100% rename from content/posts/2008-07-10-ariejannet-link-party-07102008.md rename to content/posts/2008/2008-07-10-ariejannet-link-party-07102008.md diff --git a/content/posts/2008-07-11-photography-heaven.md b/content/posts/2008/2008-07-11-photography-heaven.md similarity index 100% rename from content/posts/2008-07-11-photography-heaven.md rename to content/posts/2008/2008-07-11-photography-heaven.md diff --git a/content/posts/2008-07-17-ariejannet-link-party-07172008.md b/content/posts/2008/2008-07-17-ariejannet-link-party-07172008.md similarity index 100% rename from content/posts/2008-07-17-ariejannet-link-party-07172008.md rename to content/posts/2008/2008-07-17-ariejannet-link-party-07172008.md diff --git a/content/posts/2008-07-21-ariejannet-link-party-07212008.md b/content/posts/2008/2008-07-21-ariejannet-link-party-07212008.md similarity index 100% rename from content/posts/2008-07-21-ariejannet-link-party-07212008.md rename to content/posts/2008/2008-07-21-ariejannet-link-party-07212008.md diff --git a/content/posts/2008-08-12-ruby-on-rails-uuid-as-your-activerecord-primary-key.md b/content/posts/2008/2008-08-12-ruby-on-rails-uuid-as-your-activerecord-primary-key.md similarity index 100% rename from content/posts/2008-08-12-ruby-on-rails-uuid-as-your-activerecord-primary-key.md rename to content/posts/2008/2008-08-12-ruby-on-rails-uuid-as-your-activerecord-primary-key.md diff --git a/content/posts/2008-08-14-useless-ruby-gems-for-your-pleasure.md b/content/posts/2008/2008-08-14-useless-ruby-gems-for-your-pleasure.md similarity index 100% rename from content/posts/2008-08-14-useless-ruby-gems-for-your-pleasure.md rename to content/posts/2008/2008-08-14-useless-ruby-gems-for-your-pleasure.md diff --git a/content/posts/2008-08-17-activerecord-read-only-models.md b/content/posts/2008/2008-08-17-activerecord-read-only-models.md similarity index 100% rename from content/posts/2008-08-17-activerecord-read-only-models.md rename to content/posts/2008/2008-08-17-activerecord-read-only-models.md diff --git a/content/posts/2008-08-17-skinny-controllers-and-overweight-models.md b/content/posts/2008/2008-08-17-skinny-controllers-and-overweight-models.md similarity index 100% rename from content/posts/2008-08-17-skinny-controllers-and-overweight-models.md rename to content/posts/2008/2008-08-17-skinny-controllers-and-overweight-models.md diff --git a/content/posts/2008-09-01-leaving-for-railsconf-europe-2008.md b/content/posts/2008/2008-09-01-leaving-for-railsconf-europe-2008.md similarity index 100% rename from content/posts/2008-09-01-leaving-for-railsconf-europe-2008.md rename to content/posts/2008/2008-09-01-leaving-for-railsconf-europe-2008.md diff --git a/content/posts/2008-09-02-jruby-with-nick-sieger.md b/content/posts/2008/2008-09-02-jruby-with-nick-sieger.md similarity index 100% rename from content/posts/2008-09-02-jruby-with-nick-sieger.md rename to content/posts/2008/2008-09-02-jruby-with-nick-sieger.md diff --git a/content/posts/2008-09-02-railsconfeurope-the-first-tutorial.md b/content/posts/2008/2008-09-02-railsconfeurope-the-first-tutorial.md similarity index 100% rename from content/posts/2008-09-02-railsconfeurope-the-first-tutorial.md rename to content/posts/2008/2008-09-02-railsconfeurope-the-first-tutorial.md diff --git a/content/posts/2008-09-03-jruby-with-thomas-enebo.md b/content/posts/2008/2008-09-03-jruby-with-thomas-enebo.md similarity index 100% rename from content/posts/2008-09-03-jruby-with-thomas-enebo.md rename to content/posts/2008/2008-09-03-jruby-with-thomas-enebo.md diff --git a/content/posts/2008-09-03-panel-discussion-with-dhh-and-rails-core-members.md b/content/posts/2008/2008-09-03-panel-discussion-with-dhh-and-rails-core-members.md similarity index 100% rename from content/posts/2008-09-03-panel-discussion-with-dhh-and-rails-core-members.md rename to content/posts/2008/2008-09-03-panel-discussion-with-dhh-and-rails-core-members.md diff --git a/content/posts/2008-09-28-baseapp-a-quick-start-for-your-rails-app.md b/content/posts/2008/2008-09-28-baseapp-a-quick-start-for-your-rails-app.md similarity index 100% rename from content/posts/2008-09-28-baseapp-a-quick-start-for-your-rails-app.md rename to content/posts/2008/2008-09-28-baseapp-a-quick-start-for-your-rails-app.md diff --git a/content/posts/2008-11-05-rspecing-with-timenow.md b/content/posts/2008/2008-11-05-rspecing-with-timenow.md similarity index 97% rename from content/posts/2008-11-05-rspecing-with-timenow.md rename to content/posts/2008/2008-11-05-rspecing-with-timenow.md index c62d942..c33c0a8 100644 --- a/content/posts/2008-11-05-rspecing-with-timenow.md +++ b/content/posts/2008/2008-11-05-rspecing-with-timenow.md @@ -1,35 +1,35 @@ -+++ -date = "2008-11-05" -title = "RSpec'ing with Time.now" -tags = ["General", "Ruby", "Rails", "rspec", "Test", "time"] -slug = "rspecing-with-timenow" -+++ -I'm currently writing some RSpec tests that use Time.now. - -I want my model to calculate a duration and store the future time in the database. I've already specced the calculation of the duration, but I also want to spec that everything gets saved correctly. Here's my first spec: - -``` ruby -it "should do stuff" do - m = Model.create() - m.expires_at.should eql(Time.now + some_value) -end -``` - -This fails. - -It fails because Time.now is quite accurate and some milliseconds have passed between the two calls. - -So how do you test this kind of behaviour? I was not going to let this one beat me. Get out your gloves, because we're going to start stubbing! - -What you need to do is stub out Time#now to return a constant value within this test. This way, both calls will use the same Time.now value and thus yield the same result. This in turn makes your test pass (if the saving goes well, of course). - -``` ruby -it "should do stuff" do - @time_now = Time.parse("Feb 24 1981") - Time.stub!(:now).and_return(@time_now) - - m = Model.create() - m.expires_at.should eql(Time.now + some_value) -end -``` - ++++ +date = "2008-11-05" +title = "RSpec'ing with Time.now" +tags = ["General", "Ruby", "Rails", "rspec", "Test", "time"] +slug = "rspecing-with-timenow" ++++ +I'm currently writing some RSpec tests that use Time.now. + +I want my model to calculate a duration and store the future time in the database. I've already specced the calculation of the duration, but I also want to spec that everything gets saved correctly. Here's my first spec: + +``` ruby +it "should do stuff" do + m = Model.create() + m.expires_at.should eql(Time.now + some_value) +end +``` + +This fails. + +It fails because Time.now is quite accurate and some milliseconds have passed between the two calls. + +So how do you test this kind of behaviour? I was not going to let this one beat me. Get out your gloves, because we're going to start stubbing! + +What you need to do is stub out Time#now to return a constant value within this test. This way, both calls will use the same Time.now value and thus yield the same result. This in turn makes your test pass (if the saving goes well, of course). + +``` ruby +it "should do stuff" do + @time_now = Time.parse("Feb 24 1981") + Time.stub!(:now).and_return(@time_now) + + m = Model.create() + m.expires_at.should eql(Time.now + some_value) +end +``` + diff --git a/content/posts/2008-11-14-sql-ordering-with-null-values.md b/content/posts/2008/2008-11-14-sql-ordering-with-null-values.md similarity index 100% rename from content/posts/2008-11-14-sql-ordering-with-null-values.md rename to content/posts/2008/2008-11-14-sql-ordering-with-null-values.md diff --git a/content/posts/2008-11-27-export-csv-directly-from-mysql.md b/content/posts/2008/2008-11-27-export-csv-directly-from-mysql.md similarity index 100% rename from content/posts/2008-11-27-export-csv-directly-from-mysql.md rename to content/posts/2008/2008-11-27-export-csv-directly-from-mysql.md diff --git a/content/posts/2008-12-03-google-friendconnect-now-on-ariejannet.md b/content/posts/2008/2008-12-03-google-friendconnect-now-on-ariejannet.md similarity index 100% rename from content/posts/2008-12-03-google-friendconnect-now-on-ariejannet.md rename to content/posts/2008/2008-12-03-google-friendconnect-now-on-ariejannet.md diff --git a/content/posts/2008-12-27-twitterlicious.md b/content/posts/2008/2008-12-27-twitterlicious.md similarity index 100% rename from content/posts/2008-12-27-twitterlicious.md rename to content/posts/2008/2008-12-27-twitterlicious.md diff --git a/content/posts/2009-01-04-how-to-start-a-rails-edge-app-the-easy-way.md b/content/posts/2009/2009-01-04-how-to-start-a-rails-edge-app-the-easy-way.md similarity index 100% rename from content/posts/2009-01-04-how-to-start-a-rails-edge-app-the-easy-way.md rename to content/posts/2009/2009-01-04-how-to-start-a-rails-edge-app-the-easy-way.md diff --git a/content/posts/2009-01-30-pagerank-3-19k-hitsmonth.md b/content/posts/2009/2009-01-30-pagerank-3-19k-hitsmonth.md similarity index 100% rename from content/posts/2009-01-30-pagerank-3-19k-hitsmonth.md rename to content/posts/2009/2009-01-30-pagerank-3-19k-hitsmonth.md diff --git a/content/posts/2009-02-07-warcraft-armory-010-released.md b/content/posts/2009/2009-02-07-warcraft-armory-010-released.md similarity index 100% rename from content/posts/2009-02-07-warcraft-armory-010-released.md rename to content/posts/2009/2009-02-07-warcraft-armory-010-released.md diff --git a/content/posts/2009-03-31-may-14th-rubyfest.md b/content/posts/2009/2009-03-31-may-14th-rubyfest.md similarity index 100% rename from content/posts/2009-03-31-may-14th-rubyfest.md rename to content/posts/2009/2009-03-31-may-14th-rubyfest.md diff --git a/content/posts/2009-04-05-macbook-pro-black-screen-of-death-or-is-it-just-faking.md b/content/posts/2009/2009-04-05-macbook-pro-black-screen-of-death-or-is-it-just-faking.md similarity index 100% rename from content/posts/2009-04-05-macbook-pro-black-screen-of-death-or-is-it-just-faking.md rename to content/posts/2009/2009-04-05-macbook-pro-black-screen-of-death-or-is-it-just-faking.md diff --git a/content/posts/2009-04-19-how-to-create-a-dsa-openssl-certificate.md b/content/posts/2009/2009-04-19-how-to-create-a-dsa-openssl-certificate.md similarity index 100% rename from content/posts/2009-04-19-how-to-create-a-dsa-openssl-certificate.md rename to content/posts/2009/2009-04-19-how-to-create-a-dsa-openssl-certificate.md diff --git a/content/posts/2009-04-23-compacting-a-sqlite3-db-file.md b/content/posts/2009/2009-04-23-compacting-a-sqlite3-db-file.md similarity index 100% rename from content/posts/2009-04-23-compacting-a-sqlite3-db-file.md rename to content/posts/2009/2009-04-23-compacting-a-sqlite3-db-file.md diff --git a/content/posts/2009-04-28-available-for-iphone-development.md b/content/posts/2009/2009-04-28-available-for-iphone-development.md similarity index 100% rename from content/posts/2009-04-28-available-for-iphone-development.md rename to content/posts/2009/2009-04-28-available-for-iphone-development.md diff --git a/content/posts/2009-05-06-second-rubyfest-speaker-geoffrey-grosenbach.md b/content/posts/2009/2009-05-06-second-rubyfest-speaker-geoffrey-grosenbach.md similarity index 100% rename from content/posts/2009-05-06-second-rubyfest-speaker-geoffrey-grosenbach.md rename to content/posts/2009/2009-05-06-second-rubyfest-speaker-geoffrey-grosenbach.md diff --git a/content/posts/2009-05-22-speak-louder-i-cant-hear-you-over-the-sound-of-how-awesome-i-am.md b/content/posts/2009/2009-05-22-speak-louder-i-cant-hear-you-over-the-sound-of-how-awesome-i-am.md similarity index 100% rename from content/posts/2009-05-22-speak-louder-i-cant-hear-you-over-the-sound-of-how-awesome-i-am.md rename to content/posts/2009/2009-05-22-speak-louder-i-cant-hear-you-over-the-sound-of-how-awesome-i-am.md diff --git a/content/posts/2009-06-03-ruby-gem-imdb.md b/content/posts/2009/2009-06-03-ruby-gem-imdb.md similarity index 96% rename from content/posts/2009-06-03-ruby-gem-imdb.md rename to content/posts/2009/2009-06-03-ruby-gem-imdb.md index d3e54ca..a26dba4 100644 --- a/content/posts/2009-06-03-ruby-gem-imdb.md +++ b/content/posts/2009/2009-06-03-ruby-gem-imdb.md @@ -1,58 +1,58 @@ -+++ -date = "2009-06-03" -title = "Ruby Gem: IMDB" -tags = ["General", "Ruby", "imdb", "gem", "api"] -slug = "ruby-gem-imdb" -+++ -I just released version 0.1.0 of my IMDB gem which allows your app to search IMDB for IMDB movie ID's and access most data that's publicly available. - -## Installation - -``` shell -sudo gem install imdb -``` - -This will also install the dependencies Hpricot and HTTParty. - -## Usage - -In your project, include the gem (and possibly rubygems as well). - -``` ruby -require 'rubygems' -require 'imdb' - -search = Imdb::Search.new('Star Trek') -=> # - -puts search.movies[0..3].collect{ |m| [m.id, m.title].join(" - ") }.join("\n") -=> 0060028 - "Star Trek" (1966) (TV series) - 0796366 - Star Trek (2009) - 0092455 - "Star Trek: The Next Generation" (1987) (TV series) - 0112178 - "Star Trek: Voyager" (1995) (TV series) - -st = Imdb::Movie.new("0796366") -=> # - -st.title -=> "Star Trek" -st.year -=> 2009 -st.rating -=> 8.4 -st.cast_members[0..2].join(", ") -=> "Chris Pine, Zachary Quinto, Leonard Nimoy" -``` - -As you can see, both `Imdb::Search` and `Imdb::Movie` are lazy loading, only doing a HTTP request when you actually request data. Also, the remote HTTP data is cached trhough-out the life span of your Imdb::Movie object. - -## Documentation - -Generated RDoc documentation can be found at [http://ariejan.github.com/imdb/][1]. - -[1]: http://ariejan.github.com/imdb/ - -## Issues, feature requests, patches, the works - -Please use https://github.com/ariejan/imdb to supply patches (preferably through a pull-request) and to report issues. - ++++ +date = "2009-06-03" +title = "Ruby Gem: IMDB" +tags = ["General", "Ruby", "imdb", "gem", "api"] +slug = "ruby-gem-imdb" ++++ +I just released version 0.1.0 of my IMDB gem which allows your app to search IMDB for IMDB movie ID's and access most data that's publicly available. + +## Installation + +``` shell +sudo gem install imdb +``` + +This will also install the dependencies Hpricot and HTTParty. + +## Usage + +In your project, include the gem (and possibly rubygems as well). + +``` ruby +require 'rubygems' +require 'imdb' + +search = Imdb::Search.new('Star Trek') +=> # + +puts search.movies[0..3].collect{ |m| [m.id, m.title].join(" - ") }.join("\n") +=> 0060028 - "Star Trek" (1966) (TV series) + 0796366 - Star Trek (2009) + 0092455 - "Star Trek: The Next Generation" (1987) (TV series) + 0112178 - "Star Trek: Voyager" (1995) (TV series) + +st = Imdb::Movie.new("0796366") +=> # + +st.title +=> "Star Trek" +st.year +=> 2009 +st.rating +=> 8.4 +st.cast_members[0..2].join(", ") +=> "Chris Pine, Zachary Quinto, Leonard Nimoy" +``` + +As you can see, both `Imdb::Search` and `Imdb::Movie` are lazy loading, only doing a HTTP request when you actually request data. Also, the remote HTTP data is cached trhough-out the life span of your Imdb::Movie object. + +## Documentation + +Generated RDoc documentation can be found at [http://ariejan.github.com/imdb/][1]. + +[1]: http://ariejan.github.com/imdb/ + +## Issues, feature requests, patches, the works + +Please use https://github.com/ariejan/imdb to supply patches (preferably through a pull-request) and to report issues. + diff --git a/content/posts/2009-06-05-install-hpricot-on-ubuntu.md b/content/posts/2009/2009-06-05-install-hpricot-on-ubuntu.md similarity index 100% rename from content/posts/2009-06-05-install-hpricot-on-ubuntu.md rename to content/posts/2009/2009-06-05-install-hpricot-on-ubuntu.md diff --git a/content/posts/2009-06-07-activerecord-skipping-callbacks-like-after_save-or-after_update.md b/content/posts/2009/2009-06-07-activerecord-skipping-callbacks-like-after_save-or-after_update.md similarity index 100% rename from content/posts/2009-06-07-activerecord-skipping-callbacks-like-after_save-or-after_update.md rename to content/posts/2009/2009-06-07-activerecord-skipping-callbacks-like-after_save-or-after_update.md diff --git a/content/posts/2009-06-07-has_one-find-all-that-have-no-associated-object.md b/content/posts/2009/2009-06-07-has_one-find-all-that-have-no-associated-object.md similarity index 100% rename from content/posts/2009-06-07-has_one-find-all-that-have-no-associated-object.md rename to content/posts/2009/2009-06-07-has_one-find-all-that-have-no-associated-object.md diff --git a/content/posts/2009-06-07-imdb-0-3-0-now-including-console-utility-query-imdb-from-your-console.md b/content/posts/2009/2009-06-07-imdb-0-3-0-now-including-console-utility-query-imdb-from-your-console.md similarity index 100% rename from content/posts/2009-06-07-imdb-0-3-0-now-including-console-utility-query-imdb-from-your-console.md rename to content/posts/2009/2009-06-07-imdb-0-3-0-now-including-console-utility-query-imdb-from-your-console.md diff --git a/content/posts/2009-06-08-best-practice-the-git-development-cycle.md b/content/posts/2009/2009-06-08-best-practice-the-git-development-cycle.md similarity index 100% rename from content/posts/2009-06-08-best-practice-the-git-development-cycle.md rename to content/posts/2009/2009-06-08-best-practice-the-git-development-cycle.md diff --git a/content/posts/2009-06-14-imdb-ruby-gem-0-4-0-now-available-at-rubyforge.md b/content/posts/2009/2009-06-14-imdb-ruby-gem-0-4-0-now-available-at-rubyforge.md similarity index 100% rename from content/posts/2009-06-14-imdb-ruby-gem-0-4-0-now-available-at-rubyforge.md rename to content/posts/2009/2009-06-14-imdb-ruby-gem-0-4-0-now-available-at-rubyforge.md diff --git a/content/posts/2009-06-14-speaking-at-rails-underground.md b/content/posts/2009/2009-06-14-speaking-at-rails-underground.md similarity index 100% rename from content/posts/2009-06-14-speaking-at-rails-underground.md rename to content/posts/2009/2009-06-14-speaking-at-rails-underground.md diff --git a/content/posts/2009-08-20-once-and-for-all-rails-migrations-integer-limit-option.md b/content/posts/2009/2009-08-20-once-and-for-all-rails-migrations-integer-limit-option.md similarity index 100% rename from content/posts/2009-08-20-once-and-for-all-rails-migrations-integer-limit-option.md rename to content/posts/2009/2009-08-20-once-and-for-all-rails-migrations-integer-limit-option.md diff --git a/content/posts/2009-09-01-jinput-mac-os-x-64-bit-natives.md b/content/posts/2009/2009-09-01-jinput-mac-os-x-64-bit-natives.md similarity index 100% rename from content/posts/2009-09-01-jinput-mac-os-x-64-bit-natives.md rename to content/posts/2009/2009-09-01-jinput-mac-os-x-64-bit-natives.md diff --git a/content/posts/2009-09-03-rails-mysql-case-sensitive-strings-in-your-database.md b/content/posts/2009/2009-09-03-rails-mysql-case-sensitive-strings-in-your-database.md similarity index 100% rename from content/posts/2009-09-03-rails-mysql-case-sensitive-strings-in-your-database.md rename to content/posts/2009/2009-09-03-rails-mysql-case-sensitive-strings-in-your-database.md diff --git a/content/posts/2009-09-04-git-tag-mini-cheat-sheet.md b/content/posts/2009/2009-09-04-git-tag-mini-cheat-sheet.md similarity index 100% rename from content/posts/2009-09-04-git-tag-mini-cheat-sheet.md rename to content/posts/2009/2009-09-04-git-tag-mini-cheat-sheet.md diff --git a/content/posts/2009-09-05-git-tag-mini-cheat-sheet-revisited.md b/content/posts/2009/2009-09-05-git-tag-mini-cheat-sheet-revisited.md similarity index 100% rename from content/posts/2009-09-05-git-tag-mini-cheat-sheet-revisited.md rename to content/posts/2009/2009-09-05-git-tag-mini-cheat-sheet-revisited.md diff --git a/content/posts/2009-09-08-codaset-com-github-but-better.md b/content/posts/2009/2009-09-08-codaset-com-github-but-better.md similarity index 100% rename from content/posts/2009-09-08-codaset-com-github-but-better.md rename to content/posts/2009/2009-09-08-codaset-com-github-but-better.md diff --git a/content/posts/2009-10-13-epic-vs-awesome.md b/content/posts/2009/2009-10-13-epic-vs-awesome.md similarity index 100% rename from content/posts/2009-10-13-epic-vs-awesome.md rename to content/posts/2009/2009-10-13-epic-vs-awesome.md diff --git a/content/posts/2009-10-13-valerii-32-base-string-encoder-and-decoder.md b/content/posts/2009/2009-10-13-valerii-32-base-string-encoder-and-decoder.md similarity index 100% rename from content/posts/2009-10-13-valerii-32-base-string-encoder-and-decoder.md rename to content/posts/2009/2009-10-13-valerii-32-base-string-encoder-and-decoder.md diff --git a/content/posts/2009-10-15-git-problem-error-unable-to-create-temporary-sha1-filename.md b/content/posts/2009/2009-10-15-git-problem-error-unable-to-create-temporary-sha1-filename.md similarity index 100% rename from content/posts/2009-10-15-git-problem-error-unable-to-create-temporary-sha1-filename.md rename to content/posts/2009/2009-10-15-git-problem-error-unable-to-create-temporary-sha1-filename.md diff --git a/content/posts/2009-10-25-they-are-just-tools-people.md b/content/posts/2009/2009-10-25-they-are-just-tools-people.md similarity index 100% rename from content/posts/2009-10-25-they-are-just-tools-people.md rename to content/posts/2009/2009-10-25-they-are-just-tools-people.md diff --git a/content/posts/2009-10-26-how-to-create-and-apply-a-patch-with-git.md b/content/posts/2009/2009-10-26-how-to-create-and-apply-a-patch-with-git.md similarity index 100% rename from content/posts/2009-10-26-how-to-create-and-apply-a-patch-with-git.md rename to content/posts/2009/2009-10-26-how-to-create-and-apply-a-patch-with-git.md diff --git a/content/posts/2009-11-24-epic-textmate-theme.md b/content/posts/2009/2009-11-24-epic-textmate-theme.md similarity index 100% rename from content/posts/2009-11-24-epic-textmate-theme.md rename to content/posts/2009/2009-11-24-epic-textmate-theme.md diff --git a/content/posts/2010-01-17-the-epic-e-reading-experience-amazone-kindle.md b/content/posts/2010/2010-01-17-the-epic-e-reading-experience-amazone-kindle.md similarity index 100% rename from content/posts/2010-01-17-the-epic-e-reading-experience-amazone-kindle.md rename to content/posts/2010/2010-01-17-the-epic-e-reading-experience-amazone-kindle.md diff --git a/content/posts/2010-01-19-sign-the-petition-stop-eu-software-patents.md b/content/posts/2010/2010-01-19-sign-the-petition-stop-eu-software-patents.md similarity index 100% rename from content/posts/2010-01-19-sign-the-petition-stop-eu-software-patents.md rename to content/posts/2010/2010-01-19-sign-the-petition-stop-eu-software-patents.md diff --git a/content/posts/2010-02-02-how-to-order-your-kindle-from-the-netherlands.md b/content/posts/2010/2010-02-02-how-to-order-your-kindle-from-the-netherlands.md similarity index 100% rename from content/posts/2010-02-02-how-to-order-your-kindle-from-the-netherlands.md rename to content/posts/2010/2010-02-02-how-to-order-your-kindle-from-the-netherlands.md diff --git a/content/posts/2010-03-22-shields-up-rrrack-alert.md b/content/posts/2010/2010-03-22-shields-up-rrrack-alert.md similarity index 100% rename from content/posts/2010-03-22-shields-up-rrrack-alert.md rename to content/posts/2010/2010-03-22-shields-up-rrrack-alert.md diff --git a/content/posts/2010-03-24-ariejannet-now-in-valid-html5.md b/content/posts/2010/2010-03-24-ariejannet-now-in-valid-html5.md similarity index 100% rename from content/posts/2010-03-24-ariejannet-now-in-valid-html5.md rename to content/posts/2010/2010-03-24-ariejannet-now-in-valid-html5.md diff --git a/content/posts/2010-03-24-how-a-little-varnish-changed-my-life.md b/content/posts/2010/2010-03-24-how-a-little-varnish-changed-my-life.md similarity index 100% rename from content/posts/2010-03-24-how-a-little-varnish-changed-my-life.md rename to content/posts/2010/2010-03-24-how-a-little-varnish-changed-my-life.md diff --git a/content/posts/2010-03-25-installing-the-nokogiri-ruby-gem-on-debian.md b/content/posts/2010/2010-03-25-installing-the-nokogiri-ruby-gem-on-debian.md similarity index 100% rename from content/posts/2010-03-25-installing-the-nokogiri-ruby-gem-on-debian.md rename to content/posts/2010/2010-03-25-installing-the-nokogiri-ruby-gem-on-debian.md diff --git a/content/posts/2010-03-28-really-another-sinatra-url-shortener-in-ruby.md b/content/posts/2010/2010-03-28-really-another-sinatra-url-shortener-in-ruby.md similarity index 100% rename from content/posts/2010-03-28-really-another-sinatra-url-shortener-in-ruby.md rename to content/posts/2010/2010-03-28-really-another-sinatra-url-shortener-in-ruby.md diff --git a/content/posts/2010-03-29-announcing-firefly-a-ruby-url-shortener.md b/content/posts/2010/2010-03-29-announcing-firefly-a-ruby-url-shortener.md similarity index 100% rename from content/posts/2010-03-29-announcing-firefly-a-ruby-url-shortener.md rename to content/posts/2010/2010-03-29-announcing-firefly-a-ruby-url-shortener.md diff --git a/content/posts/2010-04-05-detect-browser-web-sockets-support.md b/content/posts/2010/2010-04-05-detect-browser-web-sockets-support.md similarity index 100% rename from content/posts/2010-04-05-detect-browser-web-sockets-support.md rename to content/posts/2010/2010-04-05-detect-browser-web-sockets-support.md diff --git a/content/posts/2010-04-13-get-ready-for-firefly-03.md b/content/posts/2010/2010-04-13-get-ready-for-firefly-03.md similarity index 100% rename from content/posts/2010-04-13-get-ready-for-firefly-03.md rename to content/posts/2010/2010-04-13-get-ready-for-firefly-03.md diff --git a/content/posts/2010-04-14-a-new-day-a-new-firefly.md b/content/posts/2010/2010-04-14-a-new-day-a-new-firefly.md similarity index 100% rename from content/posts/2010-04-14-a-new-day-a-new-firefly.md rename to content/posts/2010/2010-04-14-a-new-day-a-new-firefly.md diff --git a/content/posts/2010-04-25-ruby-version-and-gemset-in-your-bash-prompt-yes-sir.md b/content/posts/2010/2010-04-25-ruby-version-and-gemset-in-your-bash-prompt-yes-sir.md similarity index 100% rename from content/posts/2010-04-25-ruby-version-and-gemset-in-your-bash-prompt-yes-sir.md rename to content/posts/2010/2010-04-25-ruby-version-and-gemset-in-your-bash-prompt-yes-sir.md diff --git a/content/posts/2010-04-30-firefly-041-released.md b/content/posts/2010/2010-04-30-firefly-041-released.md similarity index 100% rename from content/posts/2010-04-30-firefly-041-released.md rename to content/posts/2010/2010-04-30-firefly-041-released.md diff --git a/content/posts/2010-05-17-bundler-passenger-with-rails-235-yes-please.md b/content/posts/2010/2010-05-17-bundler-passenger-with-rails-235-yes-please.md similarity index 100% rename from content/posts/2010-05-17-bundler-passenger-with-rails-235-yes-please.md rename to content/posts/2010/2010-05-17-bundler-passenger-with-rails-235-yes-please.md diff --git a/content/posts/2010-05-30-upgrading-to-mongoid-beta-6.md b/content/posts/2010/2010-05-30-upgrading-to-mongoid-beta-6.md similarity index 100% rename from content/posts/2010-05-30-upgrading-to-mongoid-beta-6.md rename to content/posts/2010/2010-05-30-upgrading-to-mongoid-beta-6.md diff --git a/content/posts/2010-06-06-firefly-043-and-firefly-client-040-released.md b/content/posts/2010/2010-06-06-firefly-043-and-firefly-client-040-released.md similarity index 100% rename from content/posts/2010-06-06-firefly-043-and-firefly-client-040-released.md rename to content/posts/2010/2010-06-06-firefly-043-and-firefly-client-040-released.md diff --git a/content/posts/2010-06-06-setup-your-own-firefly-url-shortener-in-25-minutes.md b/content/posts/2010/2010-06-06-setup-your-own-firefly-url-shortener-in-25-minutes.md similarity index 100% rename from content/posts/2010-06-06-setup-your-own-firefly-url-shortener-in-25-minutes.md rename to content/posts/2010/2010-06-06-setup-your-own-firefly-url-shortener-in-25-minutes.md diff --git a/content/posts/2010-06-07-uploading-files-with-curl.md b/content/posts/2010/2010-06-07-uploading-files-with-curl.md similarity index 100% rename from content/posts/2010-06-07-uploading-files-with-curl.md rename to content/posts/2010/2010-06-07-uploading-files-with-curl.md diff --git a/content/posts/2010-06-10-cherry-picking-specific-commits-from-another-branch.md b/content/posts/2010/2010-06-10-cherry-picking-specific-commits-from-another-branch.md similarity index 100% rename from content/posts/2010-06-10-cherry-picking-specific-commits-from-another-branch.md rename to content/posts/2010/2010-06-10-cherry-picking-specific-commits-from-another-branch.md diff --git a/content/posts/2010-07-12-screencast-firefly-url-shortener-in-less-than-25-minutes.md b/content/posts/2010/2010-07-12-screencast-firefly-url-shortener-in-less-than-25-minutes.md similarity index 100% rename from content/posts/2010-07-12-screencast-firefly-url-shortener-in-less-than-25-minutes.md rename to content/posts/2010/2010-07-12-screencast-firefly-url-shortener-in-less-than-25-minutes.md diff --git a/content/posts/2010-07-29-how-to-enable-ssh-forwarding-on-mac-os-x-snow-leopard.md b/content/posts/2010/2010-07-29-how-to-enable-ssh-forwarding-on-mac-os-x-snow-leopard.md similarity index 100% rename from content/posts/2010-07-29-how-to-enable-ssh-forwarding-on-mac-os-x-snow-leopard.md rename to content/posts/2010/2010-07-29-how-to-enable-ssh-forwarding-on-mac-os-x-snow-leopard.md diff --git a/content/posts/2010-08-09-rename-a-git-branch.md b/content/posts/2010/2010-08-09-rename-a-git-branch.md similarity index 100% rename from content/posts/2010-08-09-rename-a-git-branch.md rename to content/posts/2010/2010-08-09-rename-a-git-branch.md diff --git a/content/posts/2010-08-09-using-multiple-clipboards-in-vim.md b/content/posts/2010/2010-08-09-using-multiple-clipboards-in-vim.md similarity index 100% rename from content/posts/2010-08-09-using-multiple-clipboards-in-vim.md rename to content/posts/2010/2010-08-09-using-multiple-clipboards-in-vim.md diff --git a/content/posts/2010-08-23-resque-how-to-requeue-failed-jobs.md b/content/posts/2010/2010-08-23-resque-how-to-requeue-failed-jobs.md similarity index 100% rename from content/posts/2010-08-23-resque-how-to-requeue-failed-jobs.md rename to content/posts/2010/2010-08-23-resque-how-to-requeue-failed-jobs.md diff --git a/content/posts/2010-09-11-mass-convert-wma-to-mp3-using-ffmpeg-and-ruby.md b/content/posts/2010/2010-09-11-mass-convert-wma-to-mp3-using-ffmpeg-and-ruby.md similarity index 100% rename from content/posts/2010-09-11-mass-convert-wma-to-mp3-using-ffmpeg-and-ruby.md rename to content/posts/2010/2010-09-11-mass-convert-wma-to-mp3-using-ffmpeg-and-ruby.md diff --git a/content/posts/2010-09-28-precompile-sass-to-css-for-deployment-to-heroku.md b/content/posts/2010/2010-09-28-precompile-sass-to-css-for-deployment-to-heroku.md similarity index 100% rename from content/posts/2010-09-28-precompile-sass-to-css-for-deployment-to-heroku.md rename to content/posts/2010/2010-09-28-precompile-sass-to-css-for-deployment-to-heroku.md diff --git a/content/posts/2010-10-02-firefly-110-adds-qr-codes-for-your-shortened-urls.md b/content/posts/2010/2010-10-02-firefly-110-adds-qr-codes-for-your-shortened-urls.md similarity index 100% rename from content/posts/2010-10-02-firefly-110-adds-qr-codes-for-your-shortened-urls.md rename to content/posts/2010/2010-10-02-firefly-110-adds-qr-codes-for-your-shortened-urls.md diff --git a/content/posts/2010-10-11-setup-a-ubuntu-vpn-server.md b/content/posts/2010/2010-10-11-setup-a-ubuntu-vpn-server.md similarity index 96% rename from content/posts/2010-10-11-setup-a-ubuntu-vpn-server.md rename to content/posts/2010/2010-10-11-setup-a-ubuntu-vpn-server.md index 6631d23..c8d03a8 100644 --- a/content/posts/2010-10-11-setup-a-ubuntu-vpn-server.md +++ b/content/posts/2010/2010-10-11-setup-a-ubuntu-vpn-server.md @@ -1,51 +1,51 @@ -+++ -date = "2010-10-11" -title = "Setup a Ubuntu VPN server" -tags = ["Linux", "Ubuntu", "vpn"] -slug = "setup-a-ubuntu-vpn-server" -+++ -I recently installed Ubuntu Linux on a home server (I hate that word, but it -best describes what it is, so). Anyway, I'd like to be able to create a VPN -network between my home server and my MacbookPro, which might be anywhere in -the world. - -This first part of the tutorial describes how to setup a VPN server in Ubuntu. -~ -First, install the `pptpd` package. `pptpd` offers a `PPTP`-type VPN which is -supported by Microsoft and other network vendors. This is also the easiest to -setup. - -``` shell -sudo apt-get install pptpd -``` - -Next up, edit `/etc/pptpd.conf` with `sudo vi /etc/pptp.conf`. At the bottom add the following lines: - -``` text -localip 192.168.1.10 -remoteip 192.168.1.230-239 -``` - -Here `localip` references the IP of my home server. The `remoteip` variable -configures which IPs remote clients may use when the connect through VPN to my -network. In this case I reserve 10 IP address: 192.168.1.230 through -192.168.1.239. - -With that out of the way, let's tell `PPTP` which users to allow. Edit -`/etc/ppp/chap-secrets`, just like you did before using `sudo`. - -``` text -# client server secret IP Address -ariejan pptpd somepassword * -``` - -That's all! Yes, seriously. Just restart the `pptpd` daemon and you're good to -go. - -Now, go and watch my [PPTP VPN setup for Mac OS X Snow Leopard][1] - -_Note: This was tested on Ubuntu 10.10-amd64_ - -[1]: http://ariejan.net/2010/10/12/setup-a-pptp-vpn-connection-on-mac-os-x-snow-leopard/ - - ++++ +date = "2010-10-11" +title = "Setup a Ubuntu VPN server" +tags = ["Linux", "Ubuntu", "vpn"] +slug = "setup-a-ubuntu-vpn-server" ++++ +I recently installed Ubuntu Linux on a home server (I hate that word, but it +best describes what it is, so). Anyway, I'd like to be able to create a VPN +network between my home server and my MacbookPro, which might be anywhere in +the world. + +This first part of the tutorial describes how to setup a VPN server in Ubuntu. +~ +First, install the `pptpd` package. `pptpd` offers a `PPTP`-type VPN which is +supported by Microsoft and other network vendors. This is also the easiest to +setup. + +``` shell +sudo apt-get install pptpd +``` + +Next up, edit `/etc/pptpd.conf` with `sudo vi /etc/pptp.conf`. At the bottom add the following lines: + +``` text +localip 192.168.1.10 +remoteip 192.168.1.230-239 +``` + +Here `localip` references the IP of my home server. The `remoteip` variable +configures which IPs remote clients may use when the connect through VPN to my +network. In this case I reserve 10 IP address: 192.168.1.230 through +192.168.1.239. + +With that out of the way, let's tell `PPTP` which users to allow. Edit +`/etc/ppp/chap-secrets`, just like you did before using `sudo`. + +``` text +# client server secret IP Address +ariejan pptpd somepassword * +``` + +That's all! Yes, seriously. Just restart the `pptpd` daemon and you're good to +go. + +Now, go and watch my [PPTP VPN setup for Mac OS X Snow Leopard][1] + +_Note: This was tested on Ubuntu 10.10-amd64_ + +[1]: http://ariejan.net/2010/10/12/setup-a-pptp-vpn-connection-on-mac-os-x-snow-leopard/ + + diff --git a/content/posts/2010-10-12-setup-a-pptp-vpn-connection-on-mac-os-x-snow-leopard.md b/content/posts/2010/2010-10-12-setup-a-pptp-vpn-connection-on-mac-os-x-snow-leopard.md similarity index 100% rename from content/posts/2010-10-12-setup-a-pptp-vpn-connection-on-mac-os-x-snow-leopard.md rename to content/posts/2010/2010-10-12-setup-a-pptp-vpn-connection-on-mac-os-x-snow-leopard.md diff --git a/content/posts/2010-10-26-clear-your-mysql-password.md b/content/posts/2010/2010-10-26-clear-your-mysql-password.md similarity index 97% rename from content/posts/2010-10-26-clear-your-mysql-password.md rename to content/posts/2010/2010-10-26-clear-your-mysql-password.md index 8392812..ae5996c 100644 --- a/content/posts/2010-10-26-clear-your-mysql-password.md +++ b/content/posts/2010/2010-10-26-clear-your-mysql-password.md @@ -1,33 +1,33 @@ -+++ -date = "2010-10-26" -title = "Clear your MySQL password" -tags = ["MySQL", "development", "password"] -slug = "clear-your-mysql-password" -+++ -Most people need their MySQL database protected with at least a decent password. I agree, but in development this often causes conflicts - and I prefer to work with my MySQL datbase without all the password-hassle. - -On Ubuntu I recently installed MySQL and set a password. Here's how to remove that password so you can skip all the password stuff during development. -~ -First, connect to MySQL and check what permissions are currently set: - -``` shell -$ mysql -u root -p -use mysql; -select Host, User, Password from user; -``` - -You'll probably see three entries for the `root` user: `localhost`, `127.0.0.1` and your hostname like `hostname`. To clear the password for the root user issue the following query: - -``` sql -update user set password = '' where user = 'root'; -``` - -Optionally, you may only want to reset the password for `localhost`: - -``` sql -update user set password = '' where user = 'root' and host = 'localhost'; -``` - -Keep in mind that using no MySQL password is insecure. Always protected your MySQL database with at least a strong password in production. - - ++++ +date = "2010-10-26" +title = "Clear your MySQL password" +tags = ["MySQL", "development", "password"] +slug = "clear-your-mysql-password" ++++ +Most people need their MySQL database protected with at least a decent password. I agree, but in development this often causes conflicts - and I prefer to work with my MySQL datbase without all the password-hassle. + +On Ubuntu I recently installed MySQL and set a password. Here's how to remove that password so you can skip all the password stuff during development. +~ +First, connect to MySQL and check what permissions are currently set: + +``` shell +$ mysql -u root -p +use mysql; +select Host, User, Password from user; +``` + +You'll probably see three entries for the `root` user: `localhost`, `127.0.0.1` and your hostname like `hostname`. To clear the password for the root user issue the following query: + +``` sql +update user set password = '' where user = 'root'; +``` + +Optionally, you may only want to reset the password for `localhost`: + +``` sql +update user set password = '' where user = 'root' and host = 'localhost'; +``` + +Keep in mind that using no MySQL password is insecure. Always protected your MySQL database with at least a strong password in production. + + diff --git a/content/posts/2010-11-25-hide-last-login-on-bash-login.md b/content/posts/2010/2010-11-25-hide-last-login-on-bash-login.md similarity index 100% rename from content/posts/2010-11-25-hide-last-login-on-bash-login.md rename to content/posts/2010/2010-11-25-hide-last-login-on-bash-login.md diff --git a/content/posts/2010-12-15-why-did-errormessagesfor-disappear-from-rails-3.md b/content/posts/2010/2010-12-15-why-did-errormessagesfor-disappear-from-rails-3.md similarity index 100% rename from content/posts/2010-12-15-why-did-errormessagesfor-disappear-from-rails-3.md rename to content/posts/2010/2010-12-15-why-did-errormessagesfor-disappear-from-rails-3.md diff --git a/content/posts/2010-12-24-public-readable-amazon-s3-bucket-policy.md b/content/posts/2010/2010-12-24-public-readable-amazon-s3-bucket-policy.md similarity index 100% rename from content/posts/2010-12-24-public-readable-amazon-s3-bucket-policy.md rename to content/posts/2010/2010-12-24-public-readable-amazon-s3-bucket-policy.md diff --git a/content/posts/2010-12-31-now-powered-by-heroku.md b/content/posts/2010/2010-12-31-now-powered-by-heroku.md similarity index 100% rename from content/posts/2010-12-31-now-powered-by-heroku.md rename to content/posts/2010/2010-12-31-now-powered-by-heroku.md diff --git a/content/posts/2011-01-01-rake-task-to-sync-your-assets-to-amazon-s3cloudfront.md b/content/posts/2011/2011-01-01-rake-task-to-sync-your-assets-to-amazon-s3cloudfront.md similarity index 100% rename from content/posts/2011-01-01-rake-task-to-sync-your-assets-to-amazon-s3cloudfront.md rename to content/posts/2011/2011-01-01-rake-task-to-sync-your-assets-to-amazon-s3cloudfront.md diff --git a/content/posts/2011-02-01-hot-firefly-130-url-shortener-released.md b/content/posts/2011/2011-02-01-hot-firefly-130-url-shortener-released.md similarity index 100% rename from content/posts/2011-02-01-hot-firefly-130-url-shortener-released.md rename to content/posts/2011/2011-02-01-hot-firefly-130-url-shortener-released.md diff --git a/content/posts/2011-02-07-using-your-firefly-url-shortener-with-twitter-for-iphone.md b/content/posts/2011/2011-02-07-using-your-firefly-url-shortener-with-twitter-for-iphone.md similarity index 100% rename from content/posts/2011-02-07-using-your-firefly-url-shortener-with-twitter-for-iphone.md rename to content/posts/2011/2011-02-07-using-your-firefly-url-shortener-with-twitter-for-iphone.md diff --git a/content/posts/2011-02-11-narf-a-ruby-micro-test-framework.md b/content/posts/2011/2011-02-11-narf-a-ruby-micro-test-framework.md similarity index 100% rename from content/posts/2011-02-11-narf-a-ruby-micro-test-framework.md rename to content/posts/2011/2011-02-11-narf-a-ruby-micro-test-framework.md diff --git a/content/posts/2011-03-27-rails-3-devise-uploadify-no-flash-session-hacks.md b/content/posts/2011/2011-03-27-rails-3-devise-uploadify-no-flash-session-hacks.md similarity index 100% rename from content/posts/2011-03-27-rails-3-devise-uploadify-no-flash-session-hacks.md rename to content/posts/2011/2011-03-27-rails-3-devise-uploadify-no-flash-session-hacks.md diff --git a/content/posts/2011-04-04-rake-with-namespaces-and-default-tasks.md b/content/posts/2011/2011-04-04-rake-with-namespaces-and-default-tasks.md similarity index 96% rename from content/posts/2011-04-04-rake-with-namespaces-and-default-tasks.md rename to content/posts/2011/2011-04-04-rake-with-namespaces-and-default-tasks.md index a443ce5..fa7b72a 100644 --- a/content/posts/2011-04-04-rake-with-namespaces-and-default-tasks.md +++ b/content/posts/2011/2011-04-04-rake-with-namespaces-and-default-tasks.md @@ -1,55 +1,55 @@ -+++ -date = "2011-04-04" -title = "Rake with namespaces and default tasks" -tags = ["Ruby", "rake"] -slug = "rake-with-namespaces-and-default-tasks" -+++ -Rake is an awesome tool to automate tasks for your Ruby (or Rails) -application. In this short article I'll show you how to use namespaces -and set default tasks for them. -~ -Let me first tell you what I want to accomplish. I have a Rails -application that needs to be cleaned up occasionally. Essetially we -delete old data from the database. - -There are several models that each implement a `cleanup!` method which -takes care of cleaning up data. Now all I need is a few rake tasks to -kick off the clean up process. - -This is what I'd like: - -``` shell -rake cleanup # Cleanup everything -rake cleanup:clicks # Aggregate click stats -rake cleanup:logs # Clean old logs -``` - -Here's what I put in `lib/tasks/cleanup.rake`: - -``` ruby -namespace :cleanup do - desc "Aggregate click stats" - task :clicks => :environment do - Click.cleanup! - end - - desc "Clean old logs" - task :logs => :environment do - Log.cleanup! - end - - task :all => [:clicks, :logs] -end - -desc "Cleanup everything" -task :cleanup => 'cleanup:all' -``` - -Notice that the `cleanup:all` task does not have a description. Without -it, it won't show up when you do a `rake -T` to view available tasks. - -The task `cleanup` has the same name as the namespace and calls the -(undocumentend) `cleanup:all` task, kicking off the entire cleanup -process. - - ++++ +date = "2011-04-04" +title = "Rake with namespaces and default tasks" +tags = ["Ruby", "rake"] +slug = "rake-with-namespaces-and-default-tasks" ++++ +Rake is an awesome tool to automate tasks for your Ruby (or Rails) +application. In this short article I'll show you how to use namespaces +and set default tasks for them. +~ +Let me first tell you what I want to accomplish. I have a Rails +application that needs to be cleaned up occasionally. Essetially we +delete old data from the database. + +There are several models that each implement a `cleanup!` method which +takes care of cleaning up data. Now all I need is a few rake tasks to +kick off the clean up process. + +This is what I'd like: + +``` shell +rake cleanup # Cleanup everything +rake cleanup:clicks # Aggregate click stats +rake cleanup:logs # Clean old logs +``` + +Here's what I put in `lib/tasks/cleanup.rake`: + +``` ruby +namespace :cleanup do + desc "Aggregate click stats" + task :clicks => :environment do + Click.cleanup! + end + + desc "Clean old logs" + task :logs => :environment do + Log.cleanup! + end + + task :all => [:clicks, :logs] +end + +desc "Cleanup everything" +task :cleanup => 'cleanup:all' +``` + +Notice that the `cleanup:all` task does not have a description. Without +it, it won't show up when you do a `rake -T` to view available tasks. + +The task `cleanup` has the same name as the namespace and calls the +(undocumentend) `cleanup:all` task, kicking off the entire cleanup +process. + + diff --git a/content/posts/2011-06-10-vows-and-coffeescript.md b/content/posts/2011/2011-06-10-vows-and-coffeescript.md similarity index 96% rename from content/posts/2011-06-10-vows-and-coffeescript.md rename to content/posts/2011/2011-06-10-vows-and-coffeescript.md index 9032e63..2897ea3 100644 --- a/content/posts/2011-06-10-vows-and-coffeescript.md +++ b/content/posts/2011/2011-06-10-vows-and-coffeescript.md @@ -1,90 +1,90 @@ -+++ -date = "2011-06-10" -title = "Vows and CoffeeScript" -tags = ["javascript", "bdd", "nodejs", "coffee-script", "vows", "v8"] -slug = "vows-and-coffeescript" -+++ - -CoffeeScript is a really nice way to write JavaScript code. Combined -with NodeJS you are empowered by a very fast platform to develop -server-side applications. Of course, you want to test these apps as well. [Vows][1] is really -great way to do this. Unfortunately it's not straight forward (yet) to -set up NodeJS + CoffeeScript + Vows. - -[1]: http://vowsjs.org -~ -First off, make sure you have CoffeeScript and Vows installed. Here I -install them _globally_ so you can use the `coffee` and `vows` command -line utilities. - -``` shell -npm install -g coffee-script -npm install -g vows -``` - -Next up, in your product directory, create a directory named `test`. -Here we'll create (classic) example: `division-test.coffee` - -``` coffee -vows = require 'vows' -assert = require 'assert' - -vows - .describe('Division by zero') - .addBatch - 'when dividing a number by zero': - topic: -> 42/ 0 - - 'we get Infinity': (topic) -> - assert.equal topic, Infinity - - 'but when dividing zero by zero': - topic: -> 0 / 0 - - 'we get a value which': - 'is not a number': (topic) -> - assert.isNaN topic - - 'is not equal to itself': (topic) -> - assert.notEqual topic, topic - - .export(module) -``` - -I'm not going to explain the intimate details of Vows here, suffice it -to say that you calculate a value and store it in `topic`. Then you -perform a set of expectations. - -The magic part is the last line, `.export(module)`. In all other -examples you'll see the last command is `.run()`. This `run()` command -runs your vows immediately. - -When using coffee-script, you don't want to directly run you vows, but -gather them all together, convert them to JavaScript and then have vows -run them. - -With the `test/division-test.coffee` saved, try running `vows` from -your console. Here's the output from `vows --spec`: - -``` shell -vows --spec -♢ Division by zero - - when dividing a number by zero - ✓ we get Infinity - but when dividing zero by zero we get a value which - ✓ is not a number - ✓ is not equal to itself - -✓ OK » 3 honored (0.002s) -``` - -Another great tip is `vows -w`. This will keep vows running and monitor -your test files for changes. When a file changes, it will re-run your -vows for you. - -Happy testing! - -_Yes, I know there are issues with Coderay parsing UTF-8 characters._ - - ++++ +date = "2011-06-10" +title = "Vows and CoffeeScript" +tags = ["javascript", "bdd", "nodejs", "coffee-script", "vows", "v8"] +slug = "vows-and-coffeescript" ++++ + +CoffeeScript is a really nice way to write JavaScript code. Combined +with NodeJS you are empowered by a very fast platform to develop +server-side applications. Of course, you want to test these apps as well. [Vows][1] is really +great way to do this. Unfortunately it's not straight forward (yet) to +set up NodeJS + CoffeeScript + Vows. + +[1]: http://vowsjs.org +~ +First off, make sure you have CoffeeScript and Vows installed. Here I +install them _globally_ so you can use the `coffee` and `vows` command +line utilities. + +``` shell +npm install -g coffee-script +npm install -g vows +``` + +Next up, in your product directory, create a directory named `test`. +Here we'll create (classic) example: `division-test.coffee` + +``` coffee +vows = require 'vows' +assert = require 'assert' + +vows + .describe('Division by zero') + .addBatch + 'when dividing a number by zero': + topic: -> 42/ 0 + + 'we get Infinity': (topic) -> + assert.equal topic, Infinity + + 'but when dividing zero by zero': + topic: -> 0 / 0 + + 'we get a value which': + 'is not a number': (topic) -> + assert.isNaN topic + + 'is not equal to itself': (topic) -> + assert.notEqual topic, topic + + .export(module) +``` + +I'm not going to explain the intimate details of Vows here, suffice it +to say that you calculate a value and store it in `topic`. Then you +perform a set of expectations. + +The magic part is the last line, `.export(module)`. In all other +examples you'll see the last command is `.run()`. This `run()` command +runs your vows immediately. + +When using coffee-script, you don't want to directly run you vows, but +gather them all together, convert them to JavaScript and then have vows +run them. + +With the `test/division-test.coffee` saved, try running `vows` from +your console. Here's the output from `vows --spec`: + +``` shell +vows --spec +♢ Division by zero + + when dividing a number by zero + ✓ we get Infinity + but when dividing zero by zero we get a value which + ✓ is not a number + ✓ is not equal to itself + +✓ OK » 3 honored (0.002s) +``` + +Another great tip is `vows -w`. This will keep vows running and monitor +your test files for changes. When a file changes, it will re-run your +vows for you. + +Happy testing! + +_Yes, I know there are issues with Coderay parsing UTF-8 characters._ + + diff --git a/content/posts/2011-06-23-crowd-sourcing-your-bitcoin-mining.md b/content/posts/2011/2011-06-23-crowd-sourcing-your-bitcoin-mining.md similarity index 98% rename from content/posts/2011-06-23-crowd-sourcing-your-bitcoin-mining.md rename to content/posts/2011/2011-06-23-crowd-sourcing-your-bitcoin-mining.md index 21abfff..69974a0 100644 --- a/content/posts/2011-06-23-crowd-sourcing-your-bitcoin-mining.md +++ b/content/posts/2011/2011-06-23-crowd-sourcing-your-bitcoin-mining.md @@ -4,92 +4,92 @@ title = "Crowd sourcing your BitCoin mining" tags = ["bitcoin", "btc", "mining", "crowd-sourcing"] slug = "crowd-sourcing-your-bitcoin-mining" +++ -[BitCoin][1] is a hip new currency using peer-to-peer networking to process transactions. You can either buy it from others, or _mine_ it by solving math puzzles. Would it be possible to crowd source the _mining_ process to visitors of your website? -[1]: http://bitcoin.org -~ -### What's BitCoin anyway? -
- -
- -BitCoin (BTC) is not distributed by a central bank, but is generated by its users. In order to _mine_ BTC, your computer must solve math puzzles. When you solve the puzzle, you are awarded 50BTC. How difficult the puzzles are and how big the reward is, is all determined by the network itself - it cannot be influenced by a single entity or person. - -So, let's turn on that computer and start generating BitCoin! With a current exchange rate between $8 - $30 _per_ BitCoin, gaining 50 BTC would be quite lucrative. - -So, how long would it take to solve that math puzzle and score 50BTC, or $400 - $1500? - -Given the current difficulty (how difficult is the puzzle to solve) of _877226_ and a hash rate (the speed at which you're trying to solve the puzzle) of 6 mHashes/s you can calculate how long it would take on average before you are rewarded 50BTC. - -Using a [calculator][2] I can compute that with my current AMD Phenom II 1055T X6 (6 cores @ 2.8Ghz) it would take an average of about 20 years to generated those 50BTC. That's 0.007 BTC a day, which translates to $0.056 - $0.21 a day. That doesn't even cover the power bill for running your computer each day. - -### Can we do better than a 6 core CPU? - -Yes, we can! My system is also equipped with an ATI Radeon HD 6870 video card. I love playing games, you know ;-). The thing is, a video card is basically a very large and very fast calculator. It can perform simple operations, like the hashing required for BitCoin mining, very vast. It can do 1120 hashes *_at the same time_*. Yes, that is in parallel. - -Where the CPU could do 6 mHashes/s my GPU can do about 270 mHashes/s. Yes, my GPU is about 45 times faster at calculating hashes than my CPU. - -But, what does that mean for the time it takes to get those 50BTC? It will take 161.5 days on average. Yielding about $2.48 - $15.50 per day. That's more like it! Still, not worth leaving your day job for. - -### More power, please! - -It's possible to rig up a machine that uses even faster video cards to squeeze more mHashes/s out of it. Also, a system is not even limited to one video card, you can add up to two or four in the same computer! Imagine having four ATI Radeon 6870's. That's a whopping 1080 mHashes/s. - -1080 mHashes/s gives you an average of 40 days and 9 hours, which translates to about $9.90 - $37.14 per day. You could be making $1100 a month with that (excluding the cost for purchase and power) - -### How about The Cloud? - -You might wonder about the cloud. That big virtual pool of unlimited hardware. How about throwing some very big machines at this problem and get rich instantly. - -Well, it won't work. As we saw, CPUs are bad a generating those hashes and are thus not really a viable option for mining. - -Amazon does offer an instance type that provides two Nvidia Tesla GPUs. Unfortunately Nvidia cards don't perform well generating hashes. The cost of running one of those instances at about $50 a day. Because it performs worse than a single ATI Radeon HD 6870 you'll only lose money with this approach. - -### Team up! - -It's also possible to team up with others to mine BitCoin faster. It's been done before and the most famous example would be [Seti@Home][3]. - -Users run a program in the time their CPU is idle, contributing in the analysis of signals from space. If enough people contribute their spare CPU time, you'll get the processing power of multiple time the fastest super-computer in the world. - -Great, so let's do that for BitCoin! In the BitCoin world these are called _pools_. You can join a pool and try to solve the math puzzle together. When that happens, every participant gets a proportional share of the 50BTC for their work done. - -Imagine there are a hundred people with an ATI Radeon HD 6870 (thus doing equal amounts of work). This would result in 2.7 gHashes/s. 50 BTC would be mined in about 1 day and 14 hours. The result per day would be about the same as a single person mining on his own. - -The big difference is that when mining in a pool you get BitCoins on your balance much faster. After just a day an a half you have 0.5 BTC sitting in your account, yours to spend. A single person would have to wait 162 days for that to happen. - -### Use the Crowd, Luke! - -Now, this got me thinking. What if you could harness the power of a thousands or hundreds of thousands of CPUs, even for a short period of time? How fast would mining be? Would it be profitable? - -Then I noticed there is a website that offers a _web miner_. This is a Java applet that runs in the background of a web page. While a visitor is on your site, the applet will use spare CPU power from that users computer to generate hashes and effectively participate in a private pool. - -I ran an experiment on Ariejan.net during june 2011. I have implemented the web miner and generated BitCoin for a month using my visitors as (mostly unknowingly) test subjects. - -Ariejan.net gets between 55.000 - 65.000 page views each month. The average time per page is 40 seconds. This would yield me more than 700 hours of computing time each month. - -Using the web miner I got between 60 and 100 mHashes/s for an entire month. Doing all the mining on my own it would take 1 year and 2 months to generate 50 BTC. That's $0.75 - $2.84 per day on average. - -Because that would be too long, I participated in another pool, contributing the immense power of my websites visitors. During june you generated 1.98 BTC. About $15.85 - $59.40 when exchanged right now. - -In comparison, my ATI Radeon HD 6870 could have made between $75 and $280 in the same period of time. - -This is a nice chunk in the monthly revenue stream generated by Ariejan.net, but it would not be enough to dedicate time on writing articles on a more regular basis. - -Also, _stealing_ a visitors CPU time is ethically debatable. Personally I think it would be okay to ask a visitor to opt-in. Running the miner secretly in the background as I did for this test would not be acceptable. - -### Conclusion - -If you're in the business of mining BitCoin, crowd sourcing most likely is not an option for you. You probably don't have a web site big enough to generate enough CPU power. Using commodity hardware would yield the same or better results. - -I would be interested to see others continue this _research_. What would be the results: - - * if you asked users to opt-in only - * if you asked users to opt-out only - * on a site with 1+ million visitors - * if a miner were integrated in a game or piece of software - * if Google put a JavaScript miner on google.com that performed only 10 hashes/view. - -*Got an opinion, feel free to leave it below.* - -[2]: http://bitcoinx.com/profit/index.php +[BitCoin][1] is a hip new currency using peer-to-peer networking to process transactions. You can either buy it from others, or _mine_ it by solving math puzzles. Would it be possible to crowd source the _mining_ process to visitors of your website? +[1]: http://bitcoin.org +~ +### What's BitCoin anyway? +
+ +
+ +BitCoin (BTC) is not distributed by a central bank, but is generated by its users. In order to _mine_ BTC, your computer must solve math puzzles. When you solve the puzzle, you are awarded 50BTC. How difficult the puzzles are and how big the reward is, is all determined by the network itself - it cannot be influenced by a single entity or person. + +So, let's turn on that computer and start generating BitCoin! With a current exchange rate between $8 - $30 _per_ BitCoin, gaining 50 BTC would be quite lucrative. + +So, how long would it take to solve that math puzzle and score 50BTC, or $400 - $1500? + +Given the current difficulty (how difficult is the puzzle to solve) of _877226_ and a hash rate (the speed at which you're trying to solve the puzzle) of 6 mHashes/s you can calculate how long it would take on average before you are rewarded 50BTC. + +Using a [calculator][2] I can compute that with my current AMD Phenom II 1055T X6 (6 cores @ 2.8Ghz) it would take an average of about 20 years to generated those 50BTC. That's 0.007 BTC a day, which translates to $0.056 - $0.21 a day. That doesn't even cover the power bill for running your computer each day. + +### Can we do better than a 6 core CPU? + +Yes, we can! My system is also equipped with an ATI Radeon HD 6870 video card. I love playing games, you know ;-). The thing is, a video card is basically a very large and very fast calculator. It can perform simple operations, like the hashing required for BitCoin mining, very vast. It can do 1120 hashes *_at the same time_*. Yes, that is in parallel. + +Where the CPU could do 6 mHashes/s my GPU can do about 270 mHashes/s. Yes, my GPU is about 45 times faster at calculating hashes than my CPU. + +But, what does that mean for the time it takes to get those 50BTC? It will take 161.5 days on average. Yielding about $2.48 - $15.50 per day. That's more like it! Still, not worth leaving your day job for. + +### More power, please! + +It's possible to rig up a machine that uses even faster video cards to squeeze more mHashes/s out of it. Also, a system is not even limited to one video card, you can add up to two or four in the same computer! Imagine having four ATI Radeon 6870's. That's a whopping 1080 mHashes/s. + +1080 mHashes/s gives you an average of 40 days and 9 hours, which translates to about $9.90 - $37.14 per day. You could be making $1100 a month with that (excluding the cost for purchase and power) + +### How about The Cloud? + +You might wonder about the cloud. That big virtual pool of unlimited hardware. How about throwing some very big machines at this problem and get rich instantly. + +Well, it won't work. As we saw, CPUs are bad a generating those hashes and are thus not really a viable option for mining. + +Amazon does offer an instance type that provides two Nvidia Tesla GPUs. Unfortunately Nvidia cards don't perform well generating hashes. The cost of running one of those instances at about $50 a day. Because it performs worse than a single ATI Radeon HD 6870 you'll only lose money with this approach. + +### Team up! + +It's also possible to team up with others to mine BitCoin faster. It's been done before and the most famous example would be [Seti@Home][3]. + +Users run a program in the time their CPU is idle, contributing in the analysis of signals from space. If enough people contribute their spare CPU time, you'll get the processing power of multiple time the fastest super-computer in the world. + +Great, so let's do that for BitCoin! In the BitCoin world these are called _pools_. You can join a pool and try to solve the math puzzle together. When that happens, every participant gets a proportional share of the 50BTC for their work done. + +Imagine there are a hundred people with an ATI Radeon HD 6870 (thus doing equal amounts of work). This would result in 2.7 gHashes/s. 50 BTC would be mined in about 1 day and 14 hours. The result per day would be about the same as a single person mining on his own. + +The big difference is that when mining in a pool you get BitCoins on your balance much faster. After just a day an a half you have 0.5 BTC sitting in your account, yours to spend. A single person would have to wait 162 days for that to happen. + +### Use the Crowd, Luke! + +Now, this got me thinking. What if you could harness the power of a thousands or hundreds of thousands of CPUs, even for a short period of time? How fast would mining be? Would it be profitable? + +Then I noticed there is a website that offers a _web miner_. This is a Java applet that runs in the background of a web page. While a visitor is on your site, the applet will use spare CPU power from that users computer to generate hashes and effectively participate in a private pool. + +I ran an experiment on Ariejan.net during june 2011. I have implemented the web miner and generated BitCoin for a month using my visitors as (mostly unknowingly) test subjects. + +Ariejan.net gets between 55.000 - 65.000 page views each month. The average time per page is 40 seconds. This would yield me more than 700 hours of computing time each month. + +Using the web miner I got between 60 and 100 mHashes/s for an entire month. Doing all the mining on my own it would take 1 year and 2 months to generate 50 BTC. That's $0.75 - $2.84 per day on average. + +Because that would be too long, I participated in another pool, contributing the immense power of my websites visitors. During june you generated 1.98 BTC. About $15.85 - $59.40 when exchanged right now. + +In comparison, my ATI Radeon HD 6870 could have made between $75 and $280 in the same period of time. + +This is a nice chunk in the monthly revenue stream generated by Ariejan.net, but it would not be enough to dedicate time on writing articles on a more regular basis. + +Also, _stealing_ a visitors CPU time is ethically debatable. Personally I think it would be okay to ask a visitor to opt-in. Running the miner secretly in the background as I did for this test would not be acceptable. + +### Conclusion + +If you're in the business of mining BitCoin, crowd sourcing most likely is not an option for you. You probably don't have a web site big enough to generate enough CPU power. Using commodity hardware would yield the same or better results. + +I would be interested to see others continue this _research_. What would be the results: + + * if you asked users to opt-in only + * if you asked users to opt-out only + * on a site with 1+ million visitors + * if a miner were integrated in a game or piece of software + * if Google put a JavaScript miner on google.com that performed only 10 hashes/view. + +*Got an opinion, feel free to leave it below.* + +[2]: http://bitcoinx.com/profit/index.php [3]: http://setiathome.berkeley.edu/ diff --git a/content/posts/2011-06-24-git-what-files-were-changed-since-the-last-release.md b/content/posts/2011/2011-06-24-git-what-files-were-changed-since-the-last-release.md similarity index 100% rename from content/posts/2011-06-24-git-what-files-were-changed-since-the-last-release.md rename to content/posts/2011/2011-06-24-git-what-files-were-changed-since-the-last-release.md diff --git a/content/posts/2011-06-27-your-mac-slow-disable-spotlight-in-snow-leopard.md b/content/posts/2011/2011-06-27-your-mac-slow-disable-spotlight-in-snow-leopard.md similarity index 97% rename from content/posts/2011-06-27-your-mac-slow-disable-spotlight-in-snow-leopard.md rename to content/posts/2011/2011-06-27-your-mac-slow-disable-spotlight-in-snow-leopard.md index c92a3dc..7040459 100644 --- a/content/posts/2011-06-27-your-mac-slow-disable-spotlight-in-snow-leopard.md +++ b/content/posts/2011/2011-06-27-your-mac-slow-disable-spotlight-in-snow-leopard.md @@ -1,47 +1,47 @@ -+++ -date = "2011-06-27" -title = "Your Mac slow? Disable Spotlight in Snow Leopard" -tags = ["MacOSX", "spotlight", "diskio"] -slug = "your-mac-slow-disable-spotlight-in-snow-leopard" -+++ -For some time now I've experience my mac to be very slow. Opening Vim would take minutes. Creating a new Tab in iTerm would take more than 20 seconds. What the hell is going on - this is a brand new MacBook Pro! -~ -After investigating, using _Activity Monitor_ I discovered the following: - - * CPU's idling at 3-5% usage - * +500M free RAM - * +200G free disk space - * Negligible amount of network traffic - * Very high amount of disk I/O writes (> 450w/s) - -### What's causing disk I/O? - -So, something is using my disk. But what? The solution is to use the `iotop` utility: - -``` shell -sudo iotop -C 5 12 -``` - -A common entry here is the `mds` procoess, which has an insane amount of `BYTES`. So, this `mds` process is causing a lot of I/O, causing things to get slow. - -### What's the `mds` process do? - -A quick Google search reveals that the `mds` process is actually the Spotlight indexer service. - -### Disable Spotlight - -I don't use Spotlight at all, so let's disable it - preventing the disk I/O. - -``` shell -sudo mdutil -a -i off -``` - -That's all. Spotlight indexing disabled. After a few seconds the disk I/O dropped from ± 450w/s to 0w/s. Vim starts ups again within a seconds. I'm happy. - -### Enabling Spotlight - -If, for some obscure reason, you want to re-enable Spotlight, use the following command: - -``` shell -sudo mdutil -a -i on -``` ++++ +date = "2011-06-27" +title = "Your Mac slow? Disable Spotlight in Snow Leopard" +tags = ["MacOSX", "spotlight", "diskio"] +slug = "your-mac-slow-disable-spotlight-in-snow-leopard" ++++ +For some time now I've experience my mac to be very slow. Opening Vim would take minutes. Creating a new Tab in iTerm would take more than 20 seconds. What the hell is going on - this is a brand new MacBook Pro! +~ +After investigating, using _Activity Monitor_ I discovered the following: + + * CPU's idling at 3-5% usage + * +500M free RAM + * +200G free disk space + * Negligible amount of network traffic + * Very high amount of disk I/O writes (> 450w/s) + +### What's causing disk I/O? + +So, something is using my disk. But what? The solution is to use the `iotop` utility: + +``` shell +sudo iotop -C 5 12 +``` + +A common entry here is the `mds` procoess, which has an insane amount of `BYTES`. So, this `mds` process is causing a lot of I/O, causing things to get slow. + +### What's the `mds` process do? + +A quick Google search reveals that the `mds` process is actually the Spotlight indexer service. + +### Disable Spotlight + +I don't use Spotlight at all, so let's disable it - preventing the disk I/O. + +``` shell +sudo mdutil -a -i off +``` + +That's all. Spotlight indexing disabled. After a few seconds the disk I/O dropped from ± 450w/s to 0w/s. Vim starts ups again within a seconds. I'm happy. + +### Enabling Spotlight + +If, for some obscure reason, you want to re-enable Spotlight, use the following command: + +``` shell +sudo mdutil -a -i on +``` diff --git a/content/posts/2011-07-05-git-squash-your-latests-commits-into-one.md b/content/posts/2011/2011-07-05-git-squash-your-latests-commits-into-one.md similarity index 97% rename from content/posts/2011-07-05-git-squash-your-latests-commits-into-one.md rename to content/posts/2011/2011-07-05-git-squash-your-latests-commits-into-one.md index b052d34..5a06e4f 100644 --- a/content/posts/2011-07-05-git-squash-your-latests-commits-into-one.md +++ b/content/posts/2011/2011-07-05-git-squash-your-latests-commits-into-one.md @@ -1,48 +1,48 @@ -+++ -date = "2011-07-05" -title = "Git: Squash your latests commits into one" -tags = ["git", "rebase", "squash"] -slug = "git-squash-your-latests-commits-into-one" -+++ - -With git it's possible to squash previous commits into one. This is a great way to group certain changes together before sharing them with others. -~ -Here's how to squash some commits into one. Let's say this is your current `git log`. - -``` text -* df71a27 - (HEAD feature_x) Updated CSS for new elements (4 minutes ago) -* ba9dd9a - Added new elements to page design (15 minutes ago) -* f392171 - Added new feature X (1 day ago) -* d7322aa - (origin/feature_x) Proof of concept for feature X (3 days ago) -``` - -You have a branch `feature_x` here. You've already pushed `d7322aa` with the proof of concept of the new feature X. After that you've been working to add new element to the feature, including some changes in CSS. Now, you want to squash your last three commits in one to make your history look pretty. - -The command to accomplish that is: - -``` shell -git rebase -i HEAD~3 -``` - -This will open up your editor with the following: - -``` text -pick f392171 Added new feature X -pick ba9dd9a Added new elements to page design -pick df71a27 Updated CSS for new elements -``` - -Now you can tell git what to do with each commit. Let's keep the commit `f392171`, the one were we added our feature. We'll squash the following two commits into the first one - leaving us with one clean commit with features X in it, including the added element and CSS. - -Change your file to this: - -``` text -pick f392171 Added new feature X -squash ba9dd9a Added new elements to page design -squash df71a27 Updated CSS for new elements -``` - -When done, save and quit your editor. Git will now squash the commits into one. All done! - -Note: do not squash commits that you've already shared with others. You're changing history and it will cause trouble for others. - ++++ +date = "2011-07-05" +title = "Git: Squash your latests commits into one" +tags = ["git", "rebase", "squash"] +slug = "git-squash-your-latests-commits-into-one" ++++ + +With git it's possible to squash previous commits into one. This is a great way to group certain changes together before sharing them with others. +~ +Here's how to squash some commits into one. Let's say this is your current `git log`. + +``` text +* df71a27 - (HEAD feature_x) Updated CSS for new elements (4 minutes ago) +* ba9dd9a - Added new elements to page design (15 minutes ago) +* f392171 - Added new feature X (1 day ago) +* d7322aa - (origin/feature_x) Proof of concept for feature X (3 days ago) +``` + +You have a branch `feature_x` here. You've already pushed `d7322aa` with the proof of concept of the new feature X. After that you've been working to add new element to the feature, including some changes in CSS. Now, you want to squash your last three commits in one to make your history look pretty. + +The command to accomplish that is: + +``` shell +git rebase -i HEAD~3 +``` + +This will open up your editor with the following: + +``` text +pick f392171 Added new feature X +pick ba9dd9a Added new elements to page design +pick df71a27 Updated CSS for new elements +``` + +Now you can tell git what to do with each commit. Let's keep the commit `f392171`, the one were we added our feature. We'll squash the following two commits into the first one - leaving us with one clean commit with features X in it, including the added element and CSS. + +Change your file to this: + +``` text +pick f392171 Added new feature X +squash ba9dd9a Added new elements to page design +squash df71a27 Updated CSS for new elements +``` + +When done, save and quit your editor. Git will now squash the commits into one. All done! + +Note: do not squash commits that you've already shared with others. You're changing history and it will cause trouble for others. + diff --git a/content/posts/2011-08-24-git-log-what-did-i-do-yesterday-exactly.md b/content/posts/2011/2011-08-24-git-log-what-did-i-do-yesterday-exactly.md similarity index 97% rename from content/posts/2011-08-24-git-log-what-did-i-do-yesterday-exactly.md rename to content/posts/2011/2011-08-24-git-log-what-did-i-do-yesterday-exactly.md index cdf87ef..ca7efcd 100644 --- a/content/posts/2011-08-24-git-log-what-did-i-do-yesterday-exactly.md +++ b/content/posts/2011/2011-08-24-git-log-what-did-i-do-yesterday-exactly.md @@ -1,45 +1,45 @@ -+++ -date = "2011-08-24" -title = "Git Log: What did I do yesterday, exactly?" -tags = ["git"] -slug = "git-log-what-did-i-do-yesterday-exactly" -+++ -Sometimes you have to take your git repository's log to see what you did the day before (ideal in preparation for the daily stand-up). What I want is a clean overview of each commit messages, their author and the time. The output result should be easily grep-able so I can filter stuff I don't need out. -~ -To do this, I use the following custom `git log` command: - -``` shell -git log --pretty=format:'%Cred%h%Creset - %C(yellow)%ae%Creset - %Cgreen%cd%Creset - %s%Creset' --abbrev-commit --date=iso -``` - -The result: - -``` text -5d6ef1e - ariejan@ariejan.net - 2011-05-02 10:36:43 +0200 - Bumped to version 1.5.2 -afede9e - ariejan@ariejan.net - 2011-05-02 10:35:53 +0200 - Fixed #29 - Sharing to facebook without a title now works properly. -d9985a1 - ariejan@ariejan.net - 2011-04-23 00:13:06 -0700 - Added Travis build status to README -3e1149c - ariejan@ariejan.net - 2011-04-22 13:44:21 +0200 - Bumped version to 1.5.1 -fcab3bf - ariejan@ariejan.net - 2011-04-22 13:43:41 +0200 - Don't test on ruby 1.9.2 for now. See issue #27 -93843ec - ariejan@ariejan.net - 2011-04-22 13:42:29 +0200 - Fixed issue #28 - Share-to-* double-encodes titles -ec56315 - ariejan@ariejan.net - 2011-04-22 12:43:41 +0200 - Fixed up utf-8 encoding for ruby 1.9.2 -2146134 - ariejan@ariejan.net - 2011-04-22 12:39:37 +0200 - Bump Sinatra to 1.2.3 -c5efbf4 - ariejan@ariejan.net - 2011-04-22 12:07:41 +0200 - Truncate long URLs in the back-end to maintain a correct layout. -``` - -Now, it's easy to see what I did on april 22nd using grep - -``` shell -git log | grep 2011-04-22 -``` - -You can also filter on email address to select only specific user etc. Of course, all this could be done with git, but I'm way more comfortable using grep. - -To make life easy, you can create a shortcut for this log command. Add this to you `~/.gitconfig`: - -``` ini -[alias] - timelog = log --pretty=format:'%Cred%h%Creset - %C(yellow)%ae%Creset - %Cgreen%cd%Creset - %s%Creset' --abbrev-commit --date=iso -``` - -You can now use `git timelog` in any git repository. - ++++ +date = "2011-08-24" +title = "Git Log: What did I do yesterday, exactly?" +tags = ["git"] +slug = "git-log-what-did-i-do-yesterday-exactly" ++++ +Sometimes you have to take your git repository's log to see what you did the day before (ideal in preparation for the daily stand-up). What I want is a clean overview of each commit messages, their author and the time. The output result should be easily grep-able so I can filter stuff I don't need out. +~ +To do this, I use the following custom `git log` command: + +``` shell +git log --pretty=format:'%Cred%h%Creset - %C(yellow)%ae%Creset - %Cgreen%cd%Creset - %s%Creset' --abbrev-commit --date=iso +``` + +The result: + +``` text +5d6ef1e - ariejan@ariejan.net - 2011-05-02 10:36:43 +0200 - Bumped to version 1.5.2 +afede9e - ariejan@ariejan.net - 2011-05-02 10:35:53 +0200 - Fixed #29 - Sharing to facebook without a title now works properly. +d9985a1 - ariejan@ariejan.net - 2011-04-23 00:13:06 -0700 - Added Travis build status to README +3e1149c - ariejan@ariejan.net - 2011-04-22 13:44:21 +0200 - Bumped version to 1.5.1 +fcab3bf - ariejan@ariejan.net - 2011-04-22 13:43:41 +0200 - Don't test on ruby 1.9.2 for now. See issue #27 +93843ec - ariejan@ariejan.net - 2011-04-22 13:42:29 +0200 - Fixed issue #28 - Share-to-* double-encodes titles +ec56315 - ariejan@ariejan.net - 2011-04-22 12:43:41 +0200 - Fixed up utf-8 encoding for ruby 1.9.2 +2146134 - ariejan@ariejan.net - 2011-04-22 12:39:37 +0200 - Bump Sinatra to 1.2.3 +c5efbf4 - ariejan@ariejan.net - 2011-04-22 12:07:41 +0200 - Truncate long URLs in the back-end to maintain a correct layout. +``` + +Now, it's easy to see what I did on april 22nd using grep + +``` shell +git log | grep 2011-04-22 +``` + +You can also filter on email address to select only specific user etc. Of course, all this could be done with git, but I'm way more comfortable using grep. + +To make life easy, you can create a shortcut for this log command. Add this to you `~/.gitconfig`: + +``` ini +[alias] + timelog = log --pretty=format:'%Cred%h%Creset - %C(yellow)%ae%Creset - %Cgreen%cd%Creset - %s%Creset' --abbrev-commit --date=iso +``` + +You can now use `git timelog` in any git repository. + diff --git a/content/posts/2011-09-08-git-remove-reset-and-rollback-commits.md b/content/posts/2011/2011-09-08-git-remove-reset-and-rollback-commits.md similarity index 97% rename from content/posts/2011-09-08-git-remove-reset-and-rollback-commits.md rename to content/posts/2011/2011-09-08-git-remove-reset-and-rollback-commits.md index dfc4413..3b58c71 100644 --- a/content/posts/2011-09-08-git-remove-reset-and-rollback-commits.md +++ b/content/posts/2011/2011-09-08-git-remove-reset-and-rollback-commits.md @@ -1,42 +1,42 @@ -+++ -date = "2011-09-08" -title = "Git: remove, reset and rollback commits" -tags = ["git", "revert", "reset", "rollback"] -slug = "git-remove-reset-and-rollback-commits" -+++ -We've all been there, you committed changes you now regret. If you didn't share those commits with anyone yet, you're safe. Let me show you how to remove commits from your local repository. I'll also include an example how to roll back commits you already did share with others. -~ -Use `git log` to see your most recent commits. Let's say you want to revert the last three commits, you can run the following command: - -``` shell -git reset --hard HEAD~3 -``` - -If you only want the last commit to be removed: - -``` shell -git reset --hard HEAD~1 -``` - -HEAD~1 is a shorthand for the commit before head. But, it's also possible to roll back to a specific commit using the SHA hash. - -``` shell -git reset --hard d3f1a8 -``` - -> Please note that all your uncommitted changes will be lost when you perform `git reset --hard`. You might want to use [git stash][1] to save your uncommitted changes. - -In case you already pushed your changes to a remote repository, you can't use `git reset`, because it will wreak havoc with other people's repositories later. Instead, you could revert your commit (e.g. create a new commit, undoing a previous one). - -Note that git revert does not walk back into history, but only works on a specific commit or range of commits. To use my previous examples: - -``` shell -git revert HEAD~3..HEAD -git revert HEAD~1..HEAD -git revert d3f1a8..master -``` - -Optionally specify the `--no-commit` option to see what's being reverted. - -[1]: http://ariejan.net/2008/04/23/git-using-the-stash/ - ++++ +date = "2011-09-08" +title = "Git: remove, reset and rollback commits" +tags = ["git", "revert", "reset", "rollback"] +slug = "git-remove-reset-and-rollback-commits" ++++ +We've all been there, you committed changes you now regret. If you didn't share those commits with anyone yet, you're safe. Let me show you how to remove commits from your local repository. I'll also include an example how to roll back commits you already did share with others. +~ +Use `git log` to see your most recent commits. Let's say you want to revert the last three commits, you can run the following command: + +``` shell +git reset --hard HEAD~3 +``` + +If you only want the last commit to be removed: + +``` shell +git reset --hard HEAD~1 +``` + +HEAD~1 is a shorthand for the commit before head. But, it's also possible to roll back to a specific commit using the SHA hash. + +``` shell +git reset --hard d3f1a8 +``` + +> Please note that all your uncommitted changes will be lost when you perform `git reset --hard`. You might want to use [git stash][1] to save your uncommitted changes. + +In case you already pushed your changes to a remote repository, you can't use `git reset`, because it will wreak havoc with other people's repositories later. Instead, you could revert your commit (e.g. create a new commit, undoing a previous one). + +Note that git revert does not walk back into history, but only works on a specific commit or range of commits. To use my previous examples: + +``` shell +git revert HEAD~3..HEAD +git revert HEAD~1..HEAD +git revert d3f1a8..master +``` + +Optionally specify the `--no-commit` option to see what's being reverted. + +[1]: http://ariejan.net/2008/04/23/git-using-the-stash/ + diff --git a/content/posts/2011-09-13-git-checkout-a-single-file-from-another-commit-or-branch.md b/content/posts/2011/2011-09-13-git-checkout-a-single-file-from-another-commit-or-branch.md similarity index 100% rename from content/posts/2011-09-13-git-checkout-a-single-file-from-another-commit-or-branch.md rename to content/posts/2011/2011-09-13-git-checkout-a-single-file-from-another-commit-or-branch.md diff --git a/content/posts/2011-09-14-lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn.md b/content/posts/2011/2011-09-14-lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn.md similarity index 96% rename from content/posts/2011-09-14-lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn.md rename to content/posts/2011/2011-09-14-lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn.md index 01ce98c..c088586 100644 --- a/content/posts/2011-09-14-lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn.md +++ b/content/posts/2011/2011-09-14-lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn.md @@ -1,561 +1,561 @@ -+++ -date = "2011-09-14" -title = "Lighting fast, zero-downtime deployments with git, capistrano, nginx and Unicorn" -tags = ["Capistrano", "Rails", "git", "unicorn", "nginx", "zero-downtime", "deployment"] -slug = "lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn" -+++ -Everyone who has ever developed a web app has had to deploy it. Back in the day you simply uploaded your files with FTP and everything would be good. Today we have to clone git repositories, restart servers, set permissions, create symlinks to our configuration files, clean out caches and what not. - -## Doctor, what's wrong? - -In my opinion there are two critical problems with deployments today: - - * They are slow - * They cause downtime - -Both topics have been discussed by the likes of Twitter and Github. They have optimized their deployment process to allow for fast and _continuous deployments_. But, you are probably stuck with a default Capistrano install. As it turns out, with a little work, it's quite easy to setup the same deployment process as Github and Twitter use. - -For Ariejan.net, I've managed to get zero-downtime deployments that run in under 10 seconds. Yes, you read that right. -~ -## Let's go! - -This guide will help you setup your server and Rails 3.1 project for fast, zero-downtime deployments. I'll be using Nginx+Unicorn to serve the application, git+capistrano for fast deployments. -~ -## The shopping list - -Here's a list of ingredients you'll need: - - * A recent Ubuntu server (I used 11.04 Netty) - * Your Rails 3.1 app - * A remote git repository that contains your app - -## Assumptions - -I'm making some assumptions about your app: - - * Ruby 1.9.2 - * Rails 3.1 app using Postgres named `my_site` - * You want to use RVM and Bundler - -## Setting up your server - -There are a few things you need to setup before diving in. The first bit is run under the `root` user. - -Here's the full `apt-get` command list I used. - -``` shell -apt-get update -apt-get upgrade -y -apt-get install build-essential ruby-full libmagickcore-dev imagemagick libxml2-dev \ - libxslt1-dev git-core postgresql postgresql-client postgresql-server-dev-8.4 nginx curl -apt-get build-dep ruby1.9.1 -``` - -You'll also need a separate user account to run your app. Believe me, you don't want to run your app as `root`. I call my user `deployer`: - -``` shell -useradd -m -g staff -s /bin/bash deployer -passwd deployer -``` - -To allow `deployer` to execute commands with super-user privileges, add the following to `/etc/sudoers`. This required `deployer` to enter his password before allowing super-user access. - -``` shell -# /etc/sudoers -%staff ALL=(ALL) ALL -``` - -## Ruby and RVM - -With that done, you're ready to install `rvm`, I performed a system-wide install, so make sure you run this as root. - -``` shell -bash < <(curl -s https://rvm.beginrescueend.com/install/rvm) -``` - -Next up install the required ruby, in this case ruby-1.9.2-p290 and rubygems: - -``` shell -rvm install ruby-1.9.2-p290 -wget http://production.cf.rubygems.org/rubygems/rubygems-1.8.10.tgz -tar zxvf rubygems-1.8.10.tgz -cd rubygems-1.8.10 -ruby setup.rb -``` - -Create a `~/.gemrc` file, this sets some sane defaults for your production server: - -``` ruby -# ~/.gemrc ---- -:verbose: true -:bulk_threshold: 1000 -install: --no-ri --no-rdoc --env-shebang -:sources: -- http://gemcutter.org -- http://gems.rubyforge.org/ -- http://gems.github.com -:benchmark: false -:backtrace: false -update: --no-ri --no-rdoc --env-shebang -:update_sources: true -``` - -Also create this `~/.rvmrc` file to auto-trust your .rvmrc project files: - -``` shell -# ~/.rvmrc -rvm_trust_rvmrcs_flag=1 -``` - -_Note: do this for both `root` and the `deployer` user to avoid confusion later on._ - -Because you'll be running your app in production-mode all the time, add the following line to `/etc/environment` so you don't have to repeat it with every Rails related command you use: - -``` shell -RAILS_ENV=production -``` - -## Postgres - -I know not everybody uses Postgres, but I do. I love it and it beats the living crap out of MySQL. If you use MySQL, you'll know what to do. Here are instructions for setting up Postgres. First create the database and login as the `postgres` user: - -``` shell -sudo -u postgres createdb my_site -sudo -u postgres psql -``` - -Then execute the following SQL: - -``` sql -CREATE USER my_site WITH PASSWORD 'password'; -GRANT ALL PRIVILEGES ON DATABASE my_site TO my_site; -``` - -## Nginx - -Nginx is a great piece of Russian engineering. You'll need some configuration though: - -``` nginx -# /etc/nginx/sites-available/default -upstream my_site { - # fail_timeout=0 means we always retry an upstream even if it failed - # to return a good HTTP response (in case the Unicorn master nukes a - # single worker for timing out). - - # for UNIX domain socket setups: - server unix:/tmp/my_site.socket fail_timeout=0; -} - -server { - # if you're running multiple servers, instead of "default" you should - # put your main domain name here - listen 80 default; - - # you could put a list of other domain names this application answers - server_name my_site.example.com; - - root /home/deployer/apps/my_site/current/public; - access_log /var/log/nginx/my_site_access.log; - rewrite_log on; - - location / { - #all requests are sent to the UNIX socket - proxy_pass http://my_site; - proxy_redirect off; - - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - client_max_body_size 10m; - client_body_buffer_size 128k; - - proxy_connect_timeout 90; - proxy_send_timeout 90; - proxy_read_timeout 90; - - proxy_buffer_size 4k; - proxy_buffers 4 32k; - proxy_busy_buffers_size 64k; - proxy_temp_file_write_size 64k; - } - - # if the request is for a static resource, nginx should serve it directly - # and add a far future expires header to it, making the browser - # cache the resource and navigate faster over the website - # this probably needs some work with Rails 3.1's asset pipe_line - location ~ ^/(images|javascripts|stylesheets|system)/ { - root /home/deployer/apps/my_site/current/public; - expires max; - break; - } -} -``` - -All dandy! One more then: - -``` nginx -# /etc/nginx/nginx.conf -user deployer staff; - -# Change this depending on your hardware -worker_processes 4; -pid /var/run/nginx.pid; - -events { - worker_connections 1024; - multi_accept on; -} - -http { - sendfile on; - tcp_nopush on; - tcp_nodelay off; - # server_tokens off; - - # server_names_hash_bucket_size 64; - # server_name_in_redirect off; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - gzip on; - gzip_disable "msie6"; - - # gzip_vary on; - gzip_proxied any; - gzip_min_length 500; - # gzip_comp_level 6; - # gzip_buffers 16 8k; - # gzip_http_version 1.1; - gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; - - ## - # Virtual Host Configs - ## - - include /etc/nginx/conf.d/*.conf; - include /etc/nginx/sites-enabled/*; -} -``` - -Okay, that's Nginx for you. You should start it now, although you'll get a 500 or proxy error now: - -``` shell -/etc/init.d/nginx start -``` - -## Unicorn - -The next part involves setting up Capistrano and unicorn for your project. This is where the real magic will happen. - -You'll be doing `cap deploy` 99% of the time. This command needs to be _fast_. To accomplish this I want to utilize the power of git. Instead of having Capistrano juggle around a bunch of release directories, which is painfully slow, I want to use git to switch to the correct version of my app. This means I'll have just _one_ directory that is updated by git when it needs to be. - -Let's get started by adding some gems to your app. When done run `bundle install`. - -``` ruby - # Gemfile - gem "unicorn" - - group :development do - gem "capistrano" - end -``` - -The next step is adding a configuration file for Unicorn in `config/unicorn.rb`: - -``` ruby -# config/unicorn.rb -# Set environment to development unless something else is specified -env = ENV["RAILS_ENV"] || "development" - -# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete -# documentation. -worker_processes 4 - -# listen on both a Unix domain socket and a TCP port, -# we use a shorter backlog for quicker failover when busy -listen "/tmp/my_site.socket", :backlog => 64 - -# Preload our app for more speed -preload_app true - -# nuke workers after 30 seconds instead of 60 seconds (the default) -timeout 30 - -pid "/tmp/unicorn.my_site.pid" - -# Production specific settings -if env == "production" - # Help ensure your application will always spawn in the symlinked - # "current" directory that Capistrano sets up. - working_directory "/home/deployer/apps/my_site/current" - - # feel free to point this anywhere accessible on the filesystem - user 'deployer', 'staff' - shared_path = "/home/deployer/apps/my_site/shared" - - stderr_path "#{shared_path}/log/unicorn.stderr.log" - stdout_path "#{shared_path}/log/unicorn.stdout.log" -end - -before_fork do |server, worker| - # the following is highly recomended for Rails + "preload_app true" - # as there's no need for the master process to hold a connection - if defined?(ActiveRecord::Base) - ActiveRecord::Base.connection.disconnect! - end - - # Before forking, kill the master process that belongs to the .oldbin PID. - # This enables 0 downtime deploys. - old_pid = "/tmp/unicorn.my_site.pid.oldbin" - if File.exists?(old_pid) && server.pid != old_pid - begin - Process.kill("QUIT", File.read(old_pid).to_i) - rescue Errno::ENOENT, Errno::ESRCH - # someone else did our job for us - end - end -end - -after_fork do |server, worker| - # the following is *required* for Rails + "preload_app true", - if defined?(ActiveRecord::Base) - ActiveRecord::Base.establish_connection - end - - # if preload_app is true, then you may also want to check and - # restart any other shared sockets/descriptors such as Memcached, - # and Redis. TokyoCabinet file handles are safe to reuse - # between any number of forked children (assuming your kernel - # correctly implements pread()/pwrite() system calls) -end -``` - -Okay, as you can see there's some nice stuff in there to accomplish zero-downtime restarts. Let me tell you a bit more about that. - -Unicorn starts as a `master` process and then spawns several workers (we configured four). When you send Unicorn the 'USR2' signal it will rename itself to `master (old)` and create a new master process. The old master will keep running. - -Now, when the new master starts and forks a worker it checks the PID files of the new and old Unicorn masters. If those are different, the new master was started correctly. We can now send the old master the QUIT signal, shutting it down gracefully (e.g. let it handle open requests, but not new ones). - -All the while, you have restarted your app, without taking it down: zero downtime! - -## Capistrano - -Now for Capistrano, add the following to your `Gemfile`. - -``` ruby -# Gemfile -group :development do - gem "capistrano" -end -``` - -And generate the necessary Capistrano files. - -``` shell -capify . -``` - -Open up `config/deploy.rb` and replace it with the following. - -This deploy script does all the usual, but the special part is where you reset the release paths to the current path, making the whole release directory unnecessary. - -Also not that the `update_code` is overwritten to do a simple `git fetch` and `git reset` - this is very fast indeed! - -``` ruby -# config/deploy.rb -require "bundler/capistrano" - -set :scm, :git -set :repository, "git@codeplane.com:you/my_site.git" -set :branch, "origin/master" -set :migrate_target, :current -set :ssh_options, { :forward_agent => true } -set :rails_env, "production" -set :deploy_to, "/home/deployer/apps/my_site" -set :normalize_asset_timestamps, false - -set :user, "deployer" -set :group, "staff" -set :use_sudo, false - -role :web, "123.456.789.012" -role :app, "123.456.789.012" -role :db, "123.456.789.012", :primary => true - -set(:latest_release) { fetch(:current_path) } -set(:release_path) { fetch(:current_path) } -set(:current_release) { fetch(:current_path) } - -set(:current_revision) { capture("cd #{current_path}; git rev-parse --short HEAD").strip } -set(:latest_revision) { capture("cd #{current_path}; git rev-parse --short HEAD").strip } -set(:previous_revision) { capture("cd #{current_path}; git rev-parse --short HEAD@{1}").strip } - -default_environment["RAILS_ENV"] = 'production' - -# Use our ruby-1.9.2-p290@my_site gemset -default_environment["PATH"] = "--" -default_environment["GEM_HOME"] = "--" -default_environment["GEM_PATH"] = "--" -default_environment["RUBY_VERSION"] = "ruby-1.9.2-p290" - -default_run_options[:shell] = 'bash' - -namespace :deploy do - desc "Deploy your application" - task :default do - update - restart - end - - desc "Setup your git-based deployment app" - task :setup, :except => { :no_release => true } do - dirs = [deploy_to, shared_path] - dirs += shared_children.map { |d| File.join(shared_path, d) } - run "#{try_sudo} mkdir -p #{dirs.join(' ')} && #{try_sudo} chmod g+w #{dirs.join(' ')}" - run "git clone #{repository} #{current_path}" - end - - task :cold do - update - migrate - end - - task :update do - transaction do - update_code - end - end - - desc "Update the deployed code." - task :update_code, :except => { :no_release => true } do - run "cd #{current_path}; git fetch origin; git reset --hard #{branch}" - finalize_update - end - - desc "Update the database (overwritten to avoid symlink)" - task :migrations do - transaction do - update_code - end - migrate - restart - end - - task :finalize_update, :except => { :no_release => true } do - run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true) - - # mkdir -p is making sure that the directories are there for some SCM's that don't - # save empty folders - run <<-CMD - rm -rf #{latest_release}/log #{latest_release}/public/system #{latest_release}/tmp/pids && - mkdir -p #{latest_release}/public && - mkdir -p #{latest_release}/tmp && - ln -s #{shared_path}/log #{latest_release}/log && - ln -s #{shared_path}/system #{latest_release}/public/system && - ln -s #{shared_path}/pids #{latest_release}/tmp/pids && - ln -sf #{shared_path}/database.yml #{latest_release}/config/database.yml - CMD - - if fetch(:normalize_asset_timestamps, true) - stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S") - asset_paths = fetch(:public_children, %w(images stylesheets javascripts)).map { |p| "#{latest_release}/public/#{p}" }.join(" ") - run "find #{asset_paths} -exec touch -t #{stamp} {} ';'; true", :env => { "TZ" => "UTC" } - end - end - - desc "Zero-downtime restart of Unicorn" - task :restart, :except => { :no_release => true } do - run "kill -s USR2 `cat /tmp/unicorn.my_site.pid`" - end - - desc "Start unicorn" - task :start, :except => { :no_release => true } do - run "cd #{current_path} ; bundle exec unicorn_rails -c config/unicorn.rb -D" - end - - desc "Stop unicorn" - task :stop, :except => { :no_release => true } do - run "kill -s QUIT `cat /tmp/unicorn.my_site.pid`" - end - - namespace :rollback do - desc "Moves the repo back to the previous version of HEAD" - task :repo, :except => { :no_release => true } do - set :branch, "HEAD@{1}" - deploy.default - end - - desc "Rewrite reflog so HEAD@{1} will continue to point to at the next previous release." - task :cleanup, :except => { :no_release => true } do - run "cd #{current_path}; git reflog delete --rewrite HEAD@{1}; git reflog delete --rewrite HEAD@{1}" - end - - desc "Rolls back to the previously deployed version." - task :default do - rollback.repo - rollback.cleanup - end - end -end - -def run_rake(cmd) - run "cd #{current_path}; #{rake} #{cmd}" -end -``` - -Now there is one little thing you'll need to do. I like to run my apps, even on the server, to use their own gemset. This keeps everything clean and isolated. Login to the `deployer` account and create your gemset. Next run `rvm info` and fill the `PATH`, `GEM_HOME` and `GEM_PATH` variables accordingly. - -> Don't forget to install `bundler` in your new gemset - -## Database configuration - -I always like to keep the database configuration out of git. I'll place it in the shared directory. - -``` yaml -# /home/deployer/apps/my_site/shared/database.yml -production: - adapter: postgresql - encoding: unicode - database: my_site_production - pool: 5 - username: my_site - password: password -``` - -## First setup - -Now setup your deployment like this: - -``` shell -cap deploy:setup -``` - -This will clone your repo and link your `database.yml` file. Optionally, you may want to run migrations or upload an SQL dump to get started quickly with your app. - -## Deployments - -Whenever you have a new feature developed in a feature branch, this is the process of deploying it: - - 1. Merge `feature_branch` into `master` - 2. Run your tests to make sure everything is dandy. - 3. Push `master` - 4. Run `cap deploy` - -For Ariejan.net, step 4 takes less than 10 seconds. Unicorn is restarted with zero-downtime so users don't even notice the site was updated. - -## What's next? - -You now have fast, zero-downtime deployments working for your app. There are still some things you should to (which I might cover in some later post): - - * Tweak the nginx and Unicorn settings (especially number of workers); Perform some tests and see what works best for your app/server combination. - * Add caching to nginx (or add Varnish) - * Enable some monitoring, maybe Monit - * Crank up security a notch - * Integrate other deployment tasks like `whenever` or prepare your assets - ++++ +date = "2011-09-14" +title = "Lighting fast, zero-downtime deployments with git, capistrano, nginx and Unicorn" +tags = ["Capistrano", "Rails", "git", "unicorn", "nginx", "zero-downtime", "deployment"] +slug = "lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn" ++++ +Everyone who has ever developed a web app has had to deploy it. Back in the day you simply uploaded your files with FTP and everything would be good. Today we have to clone git repositories, restart servers, set permissions, create symlinks to our configuration files, clean out caches and what not. + +## Doctor, what's wrong? + +In my opinion there are two critical problems with deployments today: + + * They are slow + * They cause downtime + +Both topics have been discussed by the likes of Twitter and Github. They have optimized their deployment process to allow for fast and _continuous deployments_. But, you are probably stuck with a default Capistrano install. As it turns out, with a little work, it's quite easy to setup the same deployment process as Github and Twitter use. + +For Ariejan.net, I've managed to get zero-downtime deployments that run in under 10 seconds. Yes, you read that right. +~ +## Let's go! + +This guide will help you setup your server and Rails 3.1 project for fast, zero-downtime deployments. I'll be using Nginx+Unicorn to serve the application, git+capistrano for fast deployments. +~ +## The shopping list + +Here's a list of ingredients you'll need: + + * A recent Ubuntu server (I used 11.04 Netty) + * Your Rails 3.1 app + * A remote git repository that contains your app + +## Assumptions + +I'm making some assumptions about your app: + + * Ruby 1.9.2 + * Rails 3.1 app using Postgres named `my_site` + * You want to use RVM and Bundler + +## Setting up your server + +There are a few things you need to setup before diving in. The first bit is run under the `root` user. + +Here's the full `apt-get` command list I used. + +``` shell +apt-get update +apt-get upgrade -y +apt-get install build-essential ruby-full libmagickcore-dev imagemagick libxml2-dev \ + libxslt1-dev git-core postgresql postgresql-client postgresql-server-dev-8.4 nginx curl +apt-get build-dep ruby1.9.1 +``` + +You'll also need a separate user account to run your app. Believe me, you don't want to run your app as `root`. I call my user `deployer`: + +``` shell +useradd -m -g staff -s /bin/bash deployer +passwd deployer +``` + +To allow `deployer` to execute commands with super-user privileges, add the following to `/etc/sudoers`. This required `deployer` to enter his password before allowing super-user access. + +``` shell +# /etc/sudoers +%staff ALL=(ALL) ALL +``` + +## Ruby and RVM + +With that done, you're ready to install `rvm`, I performed a system-wide install, so make sure you run this as root. + +``` shell +bash < <(curl -s https://rvm.beginrescueend.com/install/rvm) +``` + +Next up install the required ruby, in this case ruby-1.9.2-p290 and rubygems: + +``` shell +rvm install ruby-1.9.2-p290 +wget http://production.cf.rubygems.org/rubygems/rubygems-1.8.10.tgz +tar zxvf rubygems-1.8.10.tgz +cd rubygems-1.8.10 +ruby setup.rb +``` + +Create a `~/.gemrc` file, this sets some sane defaults for your production server: + +``` ruby +# ~/.gemrc +--- +:verbose: true +:bulk_threshold: 1000 +install: --no-ri --no-rdoc --env-shebang +:sources: +- http://gemcutter.org +- http://gems.rubyforge.org/ +- http://gems.github.com +:benchmark: false +:backtrace: false +update: --no-ri --no-rdoc --env-shebang +:update_sources: true +``` + +Also create this `~/.rvmrc` file to auto-trust your .rvmrc project files: + +``` shell +# ~/.rvmrc +rvm_trust_rvmrcs_flag=1 +``` + +_Note: do this for both `root` and the `deployer` user to avoid confusion later on._ + +Because you'll be running your app in production-mode all the time, add the following line to `/etc/environment` so you don't have to repeat it with every Rails related command you use: + +``` shell +RAILS_ENV=production +``` + +## Postgres + +I know not everybody uses Postgres, but I do. I love it and it beats the living crap out of MySQL. If you use MySQL, you'll know what to do. Here are instructions for setting up Postgres. First create the database and login as the `postgres` user: + +``` shell +sudo -u postgres createdb my_site +sudo -u postgres psql +``` + +Then execute the following SQL: + +``` sql +CREATE USER my_site WITH PASSWORD 'password'; +GRANT ALL PRIVILEGES ON DATABASE my_site TO my_site; +``` + +## Nginx + +Nginx is a great piece of Russian engineering. You'll need some configuration though: + +``` nginx +# /etc/nginx/sites-available/default +upstream my_site { + # fail_timeout=0 means we always retry an upstream even if it failed + # to return a good HTTP response (in case the Unicorn master nukes a + # single worker for timing out). + + # for UNIX domain socket setups: + server unix:/tmp/my_site.socket fail_timeout=0; +} + +server { + # if you're running multiple servers, instead of "default" you should + # put your main domain name here + listen 80 default; + + # you could put a list of other domain names this application answers + server_name my_site.example.com; + + root /home/deployer/apps/my_site/current/public; + access_log /var/log/nginx/my_site_access.log; + rewrite_log on; + + location / { + #all requests are sent to the UNIX socket + proxy_pass http://my_site; + proxy_redirect off; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + client_max_body_size 10m; + client_body_buffer_size 128k; + + proxy_connect_timeout 90; + proxy_send_timeout 90; + proxy_read_timeout 90; + + proxy_buffer_size 4k; + proxy_buffers 4 32k; + proxy_busy_buffers_size 64k; + proxy_temp_file_write_size 64k; + } + + # if the request is for a static resource, nginx should serve it directly + # and add a far future expires header to it, making the browser + # cache the resource and navigate faster over the website + # this probably needs some work with Rails 3.1's asset pipe_line + location ~ ^/(images|javascripts|stylesheets|system)/ { + root /home/deployer/apps/my_site/current/public; + expires max; + break; + } +} +``` + +All dandy! One more then: + +``` nginx +# /etc/nginx/nginx.conf +user deployer staff; + +# Change this depending on your hardware +worker_processes 4; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; + multi_accept on; +} + +http { + sendfile on; + tcp_nopush on; + tcp_nodelay off; + # server_tokens off; + + # server_names_hash_bucket_size 64; + # server_name_in_redirect off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + gzip on; + gzip_disable "msie6"; + + # gzip_vary on; + gzip_proxied any; + gzip_min_length 500; + # gzip_comp_level 6; + # gzip_buffers 16 8k; + # gzip_http_version 1.1; + gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; + + ## + # Virtual Host Configs + ## + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} +``` + +Okay, that's Nginx for you. You should start it now, although you'll get a 500 or proxy error now: + +``` shell +/etc/init.d/nginx start +``` + +## Unicorn + +The next part involves setting up Capistrano and unicorn for your project. This is where the real magic will happen. + +You'll be doing `cap deploy` 99% of the time. This command needs to be _fast_. To accomplish this I want to utilize the power of git. Instead of having Capistrano juggle around a bunch of release directories, which is painfully slow, I want to use git to switch to the correct version of my app. This means I'll have just _one_ directory that is updated by git when it needs to be. + +Let's get started by adding some gems to your app. When done run `bundle install`. + +``` ruby + # Gemfile + gem "unicorn" + + group :development do + gem "capistrano" + end +``` + +The next step is adding a configuration file for Unicorn in `config/unicorn.rb`: + +``` ruby +# config/unicorn.rb +# Set environment to development unless something else is specified +env = ENV["RAILS_ENV"] || "development" + +# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete +# documentation. +worker_processes 4 + +# listen on both a Unix domain socket and a TCP port, +# we use a shorter backlog for quicker failover when busy +listen "/tmp/my_site.socket", :backlog => 64 + +# Preload our app for more speed +preload_app true + +# nuke workers after 30 seconds instead of 60 seconds (the default) +timeout 30 + +pid "/tmp/unicorn.my_site.pid" + +# Production specific settings +if env == "production" + # Help ensure your application will always spawn in the symlinked + # "current" directory that Capistrano sets up. + working_directory "/home/deployer/apps/my_site/current" + + # feel free to point this anywhere accessible on the filesystem + user 'deployer', 'staff' + shared_path = "/home/deployer/apps/my_site/shared" + + stderr_path "#{shared_path}/log/unicorn.stderr.log" + stdout_path "#{shared_path}/log/unicorn.stdout.log" +end + +before_fork do |server, worker| + # the following is highly recomended for Rails + "preload_app true" + # as there's no need for the master process to hold a connection + if defined?(ActiveRecord::Base) + ActiveRecord::Base.connection.disconnect! + end + + # Before forking, kill the master process that belongs to the .oldbin PID. + # This enables 0 downtime deploys. + old_pid = "/tmp/unicorn.my_site.pid.oldbin" + if File.exists?(old_pid) && server.pid != old_pid + begin + Process.kill("QUIT", File.read(old_pid).to_i) + rescue Errno::ENOENT, Errno::ESRCH + # someone else did our job for us + end + end +end + +after_fork do |server, worker| + # the following is *required* for Rails + "preload_app true", + if defined?(ActiveRecord::Base) + ActiveRecord::Base.establish_connection + end + + # if preload_app is true, then you may also want to check and + # restart any other shared sockets/descriptors such as Memcached, + # and Redis. TokyoCabinet file handles are safe to reuse + # between any number of forked children (assuming your kernel + # correctly implements pread()/pwrite() system calls) +end +``` + +Okay, as you can see there's some nice stuff in there to accomplish zero-downtime restarts. Let me tell you a bit more about that. + +Unicorn starts as a `master` process and then spawns several workers (we configured four). When you send Unicorn the 'USR2' signal it will rename itself to `master (old)` and create a new master process. The old master will keep running. + +Now, when the new master starts and forks a worker it checks the PID files of the new and old Unicorn masters. If those are different, the new master was started correctly. We can now send the old master the QUIT signal, shutting it down gracefully (e.g. let it handle open requests, but not new ones). + +All the while, you have restarted your app, without taking it down: zero downtime! + +## Capistrano + +Now for Capistrano, add the following to your `Gemfile`. + +``` ruby +# Gemfile +group :development do + gem "capistrano" +end +``` + +And generate the necessary Capistrano files. + +``` shell +capify . +``` + +Open up `config/deploy.rb` and replace it with the following. + +This deploy script does all the usual, but the special part is where you reset the release paths to the current path, making the whole release directory unnecessary. + +Also not that the `update_code` is overwritten to do a simple `git fetch` and `git reset` - this is very fast indeed! + +``` ruby +# config/deploy.rb +require "bundler/capistrano" + +set :scm, :git +set :repository, "git@codeplane.com:you/my_site.git" +set :branch, "origin/master" +set :migrate_target, :current +set :ssh_options, { :forward_agent => true } +set :rails_env, "production" +set :deploy_to, "/home/deployer/apps/my_site" +set :normalize_asset_timestamps, false + +set :user, "deployer" +set :group, "staff" +set :use_sudo, false + +role :web, "123.456.789.012" +role :app, "123.456.789.012" +role :db, "123.456.789.012", :primary => true + +set(:latest_release) { fetch(:current_path) } +set(:release_path) { fetch(:current_path) } +set(:current_release) { fetch(:current_path) } + +set(:current_revision) { capture("cd #{current_path}; git rev-parse --short HEAD").strip } +set(:latest_revision) { capture("cd #{current_path}; git rev-parse --short HEAD").strip } +set(:previous_revision) { capture("cd #{current_path}; git rev-parse --short HEAD@{1}").strip } + +default_environment["RAILS_ENV"] = 'production' + +# Use our ruby-1.9.2-p290@my_site gemset +default_environment["PATH"] = "--" +default_environment["GEM_HOME"] = "--" +default_environment["GEM_PATH"] = "--" +default_environment["RUBY_VERSION"] = "ruby-1.9.2-p290" + +default_run_options[:shell] = 'bash' + +namespace :deploy do + desc "Deploy your application" + task :default do + update + restart + end + + desc "Setup your git-based deployment app" + task :setup, :except => { :no_release => true } do + dirs = [deploy_to, shared_path] + dirs += shared_children.map { |d| File.join(shared_path, d) } + run "#{try_sudo} mkdir -p #{dirs.join(' ')} && #{try_sudo} chmod g+w #{dirs.join(' ')}" + run "git clone #{repository} #{current_path}" + end + + task :cold do + update + migrate + end + + task :update do + transaction do + update_code + end + end + + desc "Update the deployed code." + task :update_code, :except => { :no_release => true } do + run "cd #{current_path}; git fetch origin; git reset --hard #{branch}" + finalize_update + end + + desc "Update the database (overwritten to avoid symlink)" + task :migrations do + transaction do + update_code + end + migrate + restart + end + + task :finalize_update, :except => { :no_release => true } do + run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true) + + # mkdir -p is making sure that the directories are there for some SCM's that don't + # save empty folders + run <<-CMD + rm -rf #{latest_release}/log #{latest_release}/public/system #{latest_release}/tmp/pids && + mkdir -p #{latest_release}/public && + mkdir -p #{latest_release}/tmp && + ln -s #{shared_path}/log #{latest_release}/log && + ln -s #{shared_path}/system #{latest_release}/public/system && + ln -s #{shared_path}/pids #{latest_release}/tmp/pids && + ln -sf #{shared_path}/database.yml #{latest_release}/config/database.yml + CMD + + if fetch(:normalize_asset_timestamps, true) + stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S") + asset_paths = fetch(:public_children, %w(images stylesheets javascripts)).map { |p| "#{latest_release}/public/#{p}" }.join(" ") + run "find #{asset_paths} -exec touch -t #{stamp} {} ';'; true", :env => { "TZ" => "UTC" } + end + end + + desc "Zero-downtime restart of Unicorn" + task :restart, :except => { :no_release => true } do + run "kill -s USR2 `cat /tmp/unicorn.my_site.pid`" + end + + desc "Start unicorn" + task :start, :except => { :no_release => true } do + run "cd #{current_path} ; bundle exec unicorn_rails -c config/unicorn.rb -D" + end + + desc "Stop unicorn" + task :stop, :except => { :no_release => true } do + run "kill -s QUIT `cat /tmp/unicorn.my_site.pid`" + end + + namespace :rollback do + desc "Moves the repo back to the previous version of HEAD" + task :repo, :except => { :no_release => true } do + set :branch, "HEAD@{1}" + deploy.default + end + + desc "Rewrite reflog so HEAD@{1} will continue to point to at the next previous release." + task :cleanup, :except => { :no_release => true } do + run "cd #{current_path}; git reflog delete --rewrite HEAD@{1}; git reflog delete --rewrite HEAD@{1}" + end + + desc "Rolls back to the previously deployed version." + task :default do + rollback.repo + rollback.cleanup + end + end +end + +def run_rake(cmd) + run "cd #{current_path}; #{rake} #{cmd}" +end +``` + +Now there is one little thing you'll need to do. I like to run my apps, even on the server, to use their own gemset. This keeps everything clean and isolated. Login to the `deployer` account and create your gemset. Next run `rvm info` and fill the `PATH`, `GEM_HOME` and `GEM_PATH` variables accordingly. + +> Don't forget to install `bundler` in your new gemset + +## Database configuration + +I always like to keep the database configuration out of git. I'll place it in the shared directory. + +``` yaml +# /home/deployer/apps/my_site/shared/database.yml +production: + adapter: postgresql + encoding: unicode + database: my_site_production + pool: 5 + username: my_site + password: password +``` + +## First setup + +Now setup your deployment like this: + +``` shell +cap deploy:setup +``` + +This will clone your repo and link your `database.yml` file. Optionally, you may want to run migrations or upload an SQL dump to get started quickly with your app. + +## Deployments + +Whenever you have a new feature developed in a feature branch, this is the process of deploying it: + + 1. Merge `feature_branch` into `master` + 2. Run your tests to make sure everything is dandy. + 3. Push `master` + 4. Run `cap deploy` + +For Ariejan.net, step 4 takes less than 10 seconds. Unicorn is restarted with zero-downtime so users don't even notice the site was updated. + +## What's next? + +You now have fast, zero-downtime deployments working for your app. There are still some things you should to (which I might cover in some later post): + + * Tweak the nginx and Unicorn settings (especially number of workers); Perform some tests and see what works best for your app/server combination. + * Add caching to nginx (or add Varnish) + * Enable some monitoring, maybe Monit + * Crank up security a notch + * Integrate other deployment tasks like `whenever` or prepare your assets + diff --git a/content/posts/2011-09-19-capistrano-and-the-custom-maintenance-page.md b/content/posts/2011/2011-09-19-capistrano-and-the-custom-maintenance-page.md similarity index 97% rename from content/posts/2011-09-19-capistrano-and-the-custom-maintenance-page.md rename to content/posts/2011/2011-09-19-capistrano-and-the-custom-maintenance-page.md index 03ef6eb..4c9c666 100644 --- a/content/posts/2011-09-19-capistrano-and-the-custom-maintenance-page.md +++ b/content/posts/2011/2011-09-19-capistrano-and-the-custom-maintenance-page.md @@ -1,114 +1,114 @@ -+++ -date = "2011-09-19" -title = "Capistrano and the custom maintenance page" -tags = ["Capistrano", "Rails", "git", "migrations", "deployment", "maintenance"] -slug = "capistrano-and-the-custom-maintenance-page" -+++ -Randuin posted a comment on my previous [_Lighting fast, zero-downtime deployments with git, capistrano, nginx and Unicorn_][1] post asking how I handle database migrations. This is a good question. - -Database migrations, especially with large datasets, take a long time to run. They also lock your database tables which may cause all kinds of trouble. - -There's a quite an easy solution for this, offered to us by Capistrano. Unfortunately it will cause downtime for your site while the migration is running. - -[1]: http://ariejan.net/2011/09/14/lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn -~ -## Setup nginx - -The first thing you should do it update your Nginx configuration in `/etc/nginx/sites-available/default` and add the following snippet, just before the `location /`: - -``` nginx -if (-f $document_root/system/maintenance.html) { - return 503; -} - -error_page 503 @maintenance; -location @maintenance { - rewrite ^(.*)$ /system/maintenance.html last; - break; -} -``` - -As [iGEL][3] and [Anlek Consulting][4] pointed out in the comments, it's good practice to send a _503 Service Temporarily Unavailable_ HTTP code back to the client. A normal user won't notice the difference, but spiders do. Sending the 503 code will tell search engines, like Google, that your site is not available and that they should not re-index your maintenance message as the new site content. Instead, they'll come back later when your site returns a _HTTP 200_ code again. - -You can try this fairly easily by putting your site in maintenance mode (per the instructions that follow) and do a HEAD request: - -``` shell -$ curl -I http://ariejan.net -HTTP/1.1 503 Service Temporarily Unavailable -Server: nginx/0.8.54 -Date: Tue, 20 Sep 2011 18:22:35 GMT -Content-Type: text/html -Content-Length: 1276 -Connection: keep-alive -``` - -## Use Capistrano - -Now, you can run (from your own machine): - -``` shell -cap deploy:web:disable -``` - -This task will upload a generic placeholder and place it in `public/system/maintenance.html`. If nginx sees this file exists, it will render it and abort further processing. So, as long as the maintenance.html file is present, your app is not accessible. - -When you're migrations are done, you can run: - -``` shell -cap deploy:web:enable -``` - -This will have remove the `maintenance.html` file, and thus making your app accessible again. - -## Piecing it all together - -What you probably want is a separate task to deploy new code *and* run migrations. Here's the task I used: - -``` ruby -namespace :deploy do - desc "Deploy and migrate the database - this will cause downtime during migrations" - task :migrations do - transaction do - update_code - web:disable - migrate - web:enable - end - restart - end -end -``` - -## Customize your maintenance page - -Of course you want to customize the maintenance page, because, frankly, it's kind of ugly by default. This does require you write your own `deploy:web:disable` task: - -``` ruby -namespace :deploy do - namespace :web do - task :disable, :roles => :web, :except => { :no_release => true } do - require 'erb' - on_rollback { run "rm #{shared_path}/system/maintenance.html" } - - reason = ENV['REASON'] - deadline = ENV['UNTIL'] - - template = File.read("./app/views/layouts/maintenance.html.erb") - result = ERB.new(template).result(binding) - - put result, "#{shared_path}/system/maintenance.html", :mode => 0644 - end - end -end -``` - -Now you can create a maintenance page for your app at `app/views/layouts/maintentance.html.erb`. See [the original maintenance template][2] for inspiration. - -Note that you can use the environment variables `REASON` and `UNTIL` to give some info about why the app is down. - -_Keep in mind that when you put up the `maintenance.html` none of your files is accessible. This includes stylesheets and js files. Make sure to host any images and other assets on a remote server like Amazon S3._ - -[2]: https://github.com/capistrano/capistrano/blob/master/lib/capistrano/recipes/deploy/templates/maintenance.rhtml -[3]: http://igels.net -[4]: http://twitter.com/anlek - ++++ +date = "2011-09-19" +title = "Capistrano and the custom maintenance page" +tags = ["Capistrano", "Rails", "git", "migrations", "deployment", "maintenance"] +slug = "capistrano-and-the-custom-maintenance-page" ++++ +Randuin posted a comment on my previous [_Lighting fast, zero-downtime deployments with git, capistrano, nginx and Unicorn_][1] post asking how I handle database migrations. This is a good question. + +Database migrations, especially with large datasets, take a long time to run. They also lock your database tables which may cause all kinds of trouble. + +There's a quite an easy solution for this, offered to us by Capistrano. Unfortunately it will cause downtime for your site while the migration is running. + +[1]: http://ariejan.net/2011/09/14/lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn +~ +## Setup nginx + +The first thing you should do it update your Nginx configuration in `/etc/nginx/sites-available/default` and add the following snippet, just before the `location /`: + +``` nginx +if (-f $document_root/system/maintenance.html) { + return 503; +} + +error_page 503 @maintenance; +location @maintenance { + rewrite ^(.*)$ /system/maintenance.html last; + break; +} +``` + +As [iGEL][3] and [Anlek Consulting][4] pointed out in the comments, it's good practice to send a _503 Service Temporarily Unavailable_ HTTP code back to the client. A normal user won't notice the difference, but spiders do. Sending the 503 code will tell search engines, like Google, that your site is not available and that they should not re-index your maintenance message as the new site content. Instead, they'll come back later when your site returns a _HTTP 200_ code again. + +You can try this fairly easily by putting your site in maintenance mode (per the instructions that follow) and do a HEAD request: + +``` shell +$ curl -I http://ariejan.net +HTTP/1.1 503 Service Temporarily Unavailable +Server: nginx/0.8.54 +Date: Tue, 20 Sep 2011 18:22:35 GMT +Content-Type: text/html +Content-Length: 1276 +Connection: keep-alive +``` + +## Use Capistrano + +Now, you can run (from your own machine): + +``` shell +cap deploy:web:disable +``` + +This task will upload a generic placeholder and place it in `public/system/maintenance.html`. If nginx sees this file exists, it will render it and abort further processing. So, as long as the maintenance.html file is present, your app is not accessible. + +When you're migrations are done, you can run: + +``` shell +cap deploy:web:enable +``` + +This will have remove the `maintenance.html` file, and thus making your app accessible again. + +## Piecing it all together + +What you probably want is a separate task to deploy new code *and* run migrations. Here's the task I used: + +``` ruby +namespace :deploy do + desc "Deploy and migrate the database - this will cause downtime during migrations" + task :migrations do + transaction do + update_code + web:disable + migrate + web:enable + end + restart + end +end +``` + +## Customize your maintenance page + +Of course you want to customize the maintenance page, because, frankly, it's kind of ugly by default. This does require you write your own `deploy:web:disable` task: + +``` ruby +namespace :deploy do + namespace :web do + task :disable, :roles => :web, :except => { :no_release => true } do + require 'erb' + on_rollback { run "rm #{shared_path}/system/maintenance.html" } + + reason = ENV['REASON'] + deadline = ENV['UNTIL'] + + template = File.read("./app/views/layouts/maintenance.html.erb") + result = ERB.new(template).result(binding) + + put result, "#{shared_path}/system/maintenance.html", :mode => 0644 + end + end +end +``` + +Now you can create a maintenance page for your app at `app/views/layouts/maintentance.html.erb`. See [the original maintenance template][2] for inspiration. + +Note that you can use the environment variables `REASON` and `UNTIL` to give some info about why the app is down. + +_Keep in mind that when you put up the `maintenance.html` none of your files is accessible. This includes stylesheets and js files. Make sure to host any images and other assets on a remote server like Amazon S3._ + +[2]: https://github.com/capistrano/capistrano/blob/master/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +[3]: http://igels.net +[4]: http://twitter.com/anlek + diff --git a/content/posts/2011-09-24-rspec-speed-up-by-tweaking-ruby-garbage-collection.md b/content/posts/2011/2011-09-24-rspec-speed-up-by-tweaking-ruby-garbage-collection.md similarity index 97% rename from content/posts/2011-09-24-rspec-speed-up-by-tweaking-ruby-garbage-collection.md rename to content/posts/2011/2011-09-24-rspec-speed-up-by-tweaking-ruby-garbage-collection.md index 50630a7..ef3651f 100644 --- a/content/posts/2011-09-24-rspec-speed-up-by-tweaking-ruby-garbage-collection.md +++ b/content/posts/2011/2011-09-24-rspec-speed-up-by-tweaking-ruby-garbage-collection.md @@ -1,59 +1,59 @@ -+++ -date = "2011-09-24" -title = "RSpec speed-up (24.6%) by tweaking ruby garbage collection" -tags = ["Ruby", "Rails", "rspec", "speed", "garbage collection", "GC"] -slug = "rspec-speed-up-by-tweaking-ruby-garbage-collection" -+++ -[Today I learned][1] that Ruby garbage collection can be of huge importance to performance. More precisely, if Ruby does a lot of garbage collection it may slow down your code. Running garbage collection only every 10 or 20 seconds when running specs may increase performance dramatically. - -At this time specs for Ariejan.net take an average of 25.29s to run. This is not bad, but in my opinion faster specs are better. After tweaking ruby garbage collection I got my specs to run in 19.05s, a **24.6% speed increase**! -[1]: http://37signals.com/svn/posts/2742-the-road-to-faster-tests -~ -So, how do _you_ speed up _your_ tests? - -The key is that you don't want ruby to decide when to do garbage collection for you. Instead, we'll tell Ruby when to do this, and we'll let it do it every 15 seconds. - -To set this up for RSpec create a file `spec/support/deferred_garbage_collection.rb`: - -``` ruby -class DeferredGarbageCollection - - DEFERRED_GC_THRESHOLD = (ENV['DEFER_GC'] || 15.0).to_f - - @@last_gc_run = Time.now - - def self.start - GC.disable if DEFERRED_GC_THRESHOLD > 0 - end - - def self.reconsider - if DEFERRED_GC_THRESHOLD > 0 && Time.now - @@last_gc_run >= DEFERRED_GC_THRESHOLD - GC.enable - GC.start - GC.disable - @@last_gc_run = Time.now - end - end -end -``` - -Next, add the following to your `spec/spec_helper.rb` so rspec will use our deferred garbage collection. - -``` ruby -config.before(:all) do - DeferredGarbageCollection.start -end - -config.after(:all) do - DeferredGarbageCollection.reconsider -end -``` - -Now, when you run `rake spec` you should see a nice speed increase. Try to alter the threshold value a bit to see what gives your best performance: - -``` ruby -DEFER_GC=20 rake spec -``` - -Enjoy! - ++++ +date = "2011-09-24" +title = "RSpec speed-up (24.6%) by tweaking ruby garbage collection" +tags = ["Ruby", "Rails", "rspec", "speed", "garbage collection", "GC"] +slug = "rspec-speed-up-by-tweaking-ruby-garbage-collection" ++++ +[Today I learned][1] that Ruby garbage collection can be of huge importance to performance. More precisely, if Ruby does a lot of garbage collection it may slow down your code. Running garbage collection only every 10 or 20 seconds when running specs may increase performance dramatically. + +At this time specs for Ariejan.net take an average of 25.29s to run. This is not bad, but in my opinion faster specs are better. After tweaking ruby garbage collection I got my specs to run in 19.05s, a **24.6% speed increase**! +[1]: http://37signals.com/svn/posts/2742-the-road-to-faster-tests +~ +So, how do _you_ speed up _your_ tests? + +The key is that you don't want ruby to decide when to do garbage collection for you. Instead, we'll tell Ruby when to do this, and we'll let it do it every 15 seconds. + +To set this up for RSpec create a file `spec/support/deferred_garbage_collection.rb`: + +``` ruby +class DeferredGarbageCollection + + DEFERRED_GC_THRESHOLD = (ENV['DEFER_GC'] || 15.0).to_f + + @@last_gc_run = Time.now + + def self.start + GC.disable if DEFERRED_GC_THRESHOLD > 0 + end + + def self.reconsider + if DEFERRED_GC_THRESHOLD > 0 && Time.now - @@last_gc_run >= DEFERRED_GC_THRESHOLD + GC.enable + GC.start + GC.disable + @@last_gc_run = Time.now + end + end +end +``` + +Next, add the following to your `spec/spec_helper.rb` so rspec will use our deferred garbage collection. + +``` ruby +config.before(:all) do + DeferredGarbageCollection.start +end + +config.after(:all) do + DeferredGarbageCollection.reconsider +end +``` + +Now, when you run `rake spec` you should see a nice speed increase. Try to alter the threshold value a bit to see what gives your best performance: + +``` ruby +DEFER_GC=20 rake spec +``` + +Enjoy! + diff --git a/content/posts/2011-09-25-properly-testing-rails-3-scopes.md b/content/posts/2011/2011-09-25-properly-testing-rails-3-scopes.md similarity index 97% rename from content/posts/2011-09-25-properly-testing-rails-3-scopes.md rename to content/posts/2011/2011-09-25-properly-testing-rails-3-scopes.md index 01a8896..f374afc 100644 --- a/content/posts/2011-09-25-properly-testing-rails-3-scopes.md +++ b/content/posts/2011/2011-09-25-properly-testing-rails-3-scopes.md @@ -1,61 +1,61 @@ -+++ -date = "2011-09-25" -title = "Properly testing Rails 3 scopes" -tags = ["Ruby on Rails", "Rails", "rspec", "rails3", "scope", "named_scope"] -slug = "properly-testing-rails-3-scopes" -+++ -

The content of this post is no longer correct. Please read this article for details.

- -Testing scopes has always felt a bit weird to me. Normally I'd do something like this: - -``` ruby -class Post < ActiveRecord::Base - scope :published, where(:published => true) - scope :latest, order("created_at DESC") -end - -describe Post do - context 'scopes' do - before(:all) do - @first = FactoryGirl.create(:post, :created_at => 1.day.ago, :published => true) - @last = FactoryGirl.create(:post, :created_at => 4.day.ago, :published => false) - end - - it "should only return published posts" do - Post.published.should == [@first] - end - - it "should return posts in the correct order" do - Post.latest.should == [@first, @last] - end - end -end -``` - -This test is okay. It tests if the named scope does what it needs to do. And there's also the problem. Scopes are part of ActiveRecord and are already extensively tested there. All we need to do is check if we _configure_ the scope correctly. - -What we need is a way to inspect what `where` and `order` rules are set for a particular scope and make sure those are the correct ones. We can then trust ActiveRecord to keep its promise to execute the proper SQL query for us. - -Here's another test that utilizes some Rails 3 methods you may not have heard of before. - -``` ruby -describe Post do - context 'scopes' do - it "should only return published posts" do - Post.published.where_values_hash.should == {:published => true} - end - - it "should return posts in the correct order" do - Post.latest.order_values.should == ["created_at DESC"] - end - end -end -``` - -The `where_values_hash` and `order_values` allow you to inspect what a scopes doing. By writing your test this way you achieve two import goals: - - 1. You test _your_ code (instead of the ActiveRecord) - 2. You don't use the database, which is a significant speed boost - -Happy testing to you all! - ++++ +date = "2011-09-25" +title = "Properly testing Rails 3 scopes" +tags = ["Ruby on Rails", "Rails", "rspec", "rails3", "scope", "named_scope"] +slug = "properly-testing-rails-3-scopes" ++++ +

The content of this post is no longer correct. Please read this article for details.

+ +Testing scopes has always felt a bit weird to me. Normally I'd do something like this: + +``` ruby +class Post < ActiveRecord::Base + scope :published, where(:published => true) + scope :latest, order("created_at DESC") +end + +describe Post do + context 'scopes' do + before(:all) do + @first = FactoryGirl.create(:post, :created_at => 1.day.ago, :published => true) + @last = FactoryGirl.create(:post, :created_at => 4.day.ago, :published => false) + end + + it "should only return published posts" do + Post.published.should == [@first] + end + + it "should return posts in the correct order" do + Post.latest.should == [@first, @last] + end + end +end +``` + +This test is okay. It tests if the named scope does what it needs to do. And there's also the problem. Scopes are part of ActiveRecord and are already extensively tested there. All we need to do is check if we _configure_ the scope correctly. + +What we need is a way to inspect what `where` and `order` rules are set for a particular scope and make sure those are the correct ones. We can then trust ActiveRecord to keep its promise to execute the proper SQL query for us. + +Here's another test that utilizes some Rails 3 methods you may not have heard of before. + +``` ruby +describe Post do + context 'scopes' do + it "should only return published posts" do + Post.published.where_values_hash.should == {:published => true} + end + + it "should return posts in the correct order" do + Post.latest.order_values.should == ["created_at DESC"] + end + end +end +``` + +The `where_values_hash` and `order_values` allow you to inspect what a scopes doing. By writing your test this way you achieve two import goals: + + 1. You test _your_ code (instead of the ActiveRecord) + 2. You don't use the database, which is a significant speed boost + +Happy testing to you all! + diff --git a/content/posts/2011-10-09-testing-rails-3-scopes-revisited.md b/content/posts/2011/2011-10-09-testing-rails-3-scopes-revisited.md similarity index 97% rename from content/posts/2011-10-09-testing-rails-3-scopes-revisited.md rename to content/posts/2011/2011-10-09-testing-rails-3-scopes-revisited.md index 9e53817..ddd69b1 100644 --- a/content/posts/2011-10-09-testing-rails-3-scopes-revisited.md +++ b/content/posts/2011/2011-10-09-testing-rails-3-scopes-revisited.md @@ -1,39 +1,39 @@ -+++ -date = "2011-10-09" -title = "Testing Rails 3 scopes revisited" -tags = ["Ruby on Rails", "Rails", "rspec", "rails3", "scope", "named_scope"] -slug = "testing-rails-3-scopes-revisited" -+++ -In my [previous article][pa] I told you about how I like to tests my scope. There was a fair amount of criticism on that post and after considering it all (and hearing Corey Haines' talk on Arrrrcamp last friday), I'm convinced it's the wrong path. - -In essence Rails allows you to create a scope to generate a custom database query for you. Now, if you only test your configuration of Rails (as I did in my previous post), you don't know if that scope works or not. If a piece directly relies on your database, you must test it against your database. - -Also, your configuration may be correct, but what happens when you upgrade to a newer version of Rails or PostgreSQL? Does that configuration still work as advertised? - -So, this is the proper way of testing your scopes: - -``` ruby -class Post < ActiveRecord::Base - scope :latest, order("created_at DESC") -end - -describe Post do - context 'scopes' do - before(:all) do - @first = FactoryGirl.create(:post, :created_at => 1.day.ago) - @last = FactoryGirl.create(:post, :created_at => 4.day.ago) - end - - it "should return posts in the correct order" do - Post.latest.should == [@first, @last] - end - end -end -``` - -## A note on speed - -So, you now have to utilize the whole Rails stack _and_ hit your database to perform this test, which is slow. But then you don't upgrade Rails or your database very often, so you don't have run this spec with every TDD Baby Step you take. (More on that in a later post.) - -[pa]: http://ariejan.net/2011/09/25/properly-testing-rails-3-scopes - ++++ +date = "2011-10-09" +title = "Testing Rails 3 scopes revisited" +tags = ["Ruby on Rails", "Rails", "rspec", "rails3", "scope", "named_scope"] +slug = "testing-rails-3-scopes-revisited" ++++ +In my [previous article][pa] I told you about how I like to tests my scope. There was a fair amount of criticism on that post and after considering it all (and hearing Corey Haines' talk on Arrrrcamp last friday), I'm convinced it's the wrong path. + +In essence Rails allows you to create a scope to generate a custom database query for you. Now, if you only test your configuration of Rails (as I did in my previous post), you don't know if that scope works or not. If a piece directly relies on your database, you must test it against your database. + +Also, your configuration may be correct, but what happens when you upgrade to a newer version of Rails or PostgreSQL? Does that configuration still work as advertised? + +So, this is the proper way of testing your scopes: + +``` ruby +class Post < ActiveRecord::Base + scope :latest, order("created_at DESC") +end + +describe Post do + context 'scopes' do + before(:all) do + @first = FactoryGirl.create(:post, :created_at => 1.day.ago) + @last = FactoryGirl.create(:post, :created_at => 4.day.ago) + end + + it "should return posts in the correct order" do + Post.latest.should == [@first, @last] + end + end +end +``` + +## A note on speed + +So, you now have to utilize the whole Rails stack _and_ hit your database to perform this test, which is slow. But then you don't upgrade Rails or your database very often, so you don't have run this spec with every TDD Baby Step you take. (More on that in a later post.) + +[pa]: http://ariejan.net/2011/09/25/properly-testing-rails-3-scopes + diff --git a/content/posts/2011-10-13-fast-specs-run-your-specs-in-less-than-1-second.md b/content/posts/2011/2011-10-13-fast-specs-run-your-specs-in-less-than-1-second.md similarity index 97% rename from content/posts/2011-10-13-fast-specs-run-your-specs-in-less-than-1-second.md rename to content/posts/2011/2011-10-13-fast-specs-run-your-specs-in-less-than-1-second.md index 03dbd9b..ee8f2f7 100644 --- a/content/posts/2011-10-13-fast-specs-run-your-specs-in-less-than-1-second.md +++ b/content/posts/2011/2011-10-13-fast-specs-run-your-specs-in-less-than-1-second.md @@ -1,239 +1,239 @@ -+++ -date = "2011-10-13" -title = "Fast specs - Run your specs in less than 1 second" -tags = ["Ruby", "Rails", "rspec", "testing", "bdd", "tdd", "cucumber", "fast_spec", "fastspec", "coreyhaines"] -slug = "fast-specs-run-your-specs-in-less-than-1-second" -+++ -Okay, let me clarify that title first. I, as most of you, have two sets of tests for my Rails application: rspec and cucumber. rspec heavily focusses on testing models and business logic while cucumber focusses on testing the entire application stack and user interaction. - -The problem is that as your app grows, your test set grows - and so does the time it takes to run those tests. - -_This post is inspired by [Corey Haines](http://coreyhaines.com)' talk at [Arrrrcamp](http://arrrrcamp.be) (Oct 2011) and my own experience with writing fast specs._ - -## Red - Green - Refactor - -If you do TDD/BDD you most likely follow the Red-Green-Refactor pattern: - -1. Write one test, and see it fail (red) -2. Write the most minimal implementation to satisfy that test, and see it pass (green) -3. Refactor your code to look/perform better (refactor) -4. Repeat - -But what if your test suite takes >30 seconds to run. You write a test, then wait 30 seconds to see the test fail. You then write the simple implementation, wait 30 seconds. Oops, you made a typo - fix it, wait 30 seconds. Now it passes. Refactor, again wait 30 seconds. - -I think this scenario is very familiar for many rails developers. - -## Take a closer look - -So, let's take a closer look at a real-world example. - -This is a `Post` model, it `belongs_to` and author and it can give you a summary of an article by returning the text above a '~' marker. - -``` ruby -# app/models/post.rb -class Post < ActiveRecord::Base - DELIMITER = "~\n" - - belongs_to :author - - def summary - summary = if body =~ /#{DELIMITER}/i - body.split(/#{DELIMITER}/i).first.strip - else - body - end - end -end -``` - -This is a spec that's defined for the `Post` model: - -``` ruby -# spec/models/post_spec.rb -require 'spec/helper' - -describe Post do - context "summary" do - it "should return the summary" do - post = FactoryGirl.build(:post, :body => "Summary\n~\nNo summary.") - post.summary.should == "Summary" - end - end -end -``` - -Running this spec would take at least 10 seconds. Running `time rspec spec/models/post_spec.rb` woudl output something like this: - -``` text -Finished in 0.05523 seconds -real 0m10.387s -``` - -This means that running the actual spec took 0.05s, but running the entire command took 10 seconds. What is slowing us down? - -## Dependencies - -As you see in the spec above I use `FactoryGirl.build` instead of `FactoryGirl.create` to prevent interacting with the database. I do this because hitting the database slows down your test. - -I removed the database dependency in order for my test to run faster. - -What other dependencies are there that could be removed in order to test the summary functionality? - -Any idea? - -Yes! - -Rails. - -## Rails is a dependency to your app - -You have a Rails-app. But Rails is not your app, it's a dependency, just like the `pg` and `haml` gems are dependencies. - -Loading the entire Rails stack takes quite some time. And just like with the database dependency we must ask ourselves: do we really need Rails to perform this test? - -There are a lot of scenarios where the answer to that question is _NO_. - -## Specs without Rails - -This may seem a bit weird at first, but let's take another look at the `Post` model: - -``` ruby -# app/models/post.rb -class Post < ActiveRecord::Base - DELIMITER = "~\n" - - belongs_to :author - - def summary - summary = if body =~ /#{DELIMITER}/i - body.split(/#{DELIMITER}/i).first.strip - else - body - end - end -end -``` - -The `summary` method does not interact with the `Post` model at all, except that it access the `body` attribute. But the `body` attribute is just a `String`. - -So, if we wanted to test the `summary` method and remove all Rails dependencies, we'd have to remove ActiveRecord. - -Consider this: - -``` ruby -# app/logic/myapp/summary.rb -module MyApp - class Summary - def self.for(text, delimiter) - summary = if text =~ /#{delimiter}/i - text.split(/#{delimiter}/i).first.strip - else - text - end - end - end -end -``` - -I think you can quickly see that this method does exactly the same as `Post#summary`. But it does not have any dependency to ActiveRecord. - -Could we rewrite our test for this new class? - - # fast_spec/myapp/summary_spec.rb - require 'myapp/summary' - - describe MyApp::Summary do - it "should return the summary" do - MyApp::Summary.for("Summary\n~\nNo summary.", "~\n").should == "Summary" - end - end - -That looks good! Note that this spec _does not_ include `spec_helper`. `spec_helper` is responsible for loading up your test environment, which normally includes all your app dependencies, including Rails. - -## Your new Post model - -The `Post` model should also be updated, of course to utilise this new class. - -``` ruby -# app/models/post.rb -class Post < ActiveRecord::Base - DELIMITER = "~\n" - - belongs_to :author - - def summary - MyApp::Summary.for(body, DELIMITER) - end -end -``` - -The spec for `Post` should also be changed. Since we already have tested that `MyApp::Summary#for` returns the right summary for a given text and delimiter, all we have left to do is make sure that `Post#summary` calls it correctly. - -``` ruby -# spec/models/post_spec.rb -require 'spec/helper' - -describe Post do - context "summary" do - it "should return the summary" do - post = FactoryGirl.build(:post) - MyApp::Summary.should_receive(:for).with(post.body, Post::DELIMITER) - post.summary - end - end -end -``` - -## Running fast specs - -The files above are located in `fast_spec` and `app/logic`. I do this because I want to separate my fast_specs so I can run them independtly from my normal specs. - -Running fast specs works like this: - -``` shell -rspec -I app/logic fast_spec -``` - -Try it out with `time rspec -I app/logic fast_spec`: - -``` text -Finished in 0.03223 seconds -real 0m0.421s -``` - -That's your same spec, down from about 10 seconds to 0.5 second. - -## The big picture - -By now you have seen that you can extract business logic into a seperate class. You've also seen that you can write tests that don't depend on Rails and run amazingly fast. - -Of course you ask, how does this relate to normal RSpec and Cucumber tests? - -My opinion is that your fast_specs test business logic that does not relate to anything Rails specific, like making calculations, processing text, et cetera. - -When you make changes to your business logic, you can test is very quickly. This shortens your TDD cycle and allows you to focus more on the task at hand (instead of waiting for your tests). - -RSpec tests are there to test integration with your dependencies like Rails. This is the place where test scopes and mailers. - -Cucumber still has its place to test user interaction with your app. Can a user still click the 'Order' button and get the proper response from our app. - -RSpec and Cucumber will now be ran less often. Maybe only before you commit code - or maybe have your CI run them for you? - -## Added benefit - Design - -An added bonus of TDD is that your tests dictate the design of your app. By using fast_spec you force your business logic into separate classes. This makes them even more re-usable than normal Rails models. - -Your ActiveRecord models now become cleaner and are more a _configuration of Rails_ than anything else. - -By doing this your app will become way more maintainable, easier to test, faster to test and your code will be more re-usable. What's not to like? - -## Where to go from here? - -As Corey Haines put it: - -> Try to extract one single method from your app into a fast_spec. Just one. When you have that one spec running so fast it's easy to add more. - -This would also be my advise to you. Try to extract one piece of functionality from a model into a fast_spec. It may be difficult at first, but try it and see the results. - -Then, when you have that one example working, add more. - ++++ +date = "2011-10-13" +title = "Fast specs - Run your specs in less than 1 second" +tags = ["Ruby", "Rails", "rspec", "testing", "bdd", "tdd", "cucumber", "fast_spec", "fastspec", "coreyhaines"] +slug = "fast-specs-run-your-specs-in-less-than-1-second" ++++ +Okay, let me clarify that title first. I, as most of you, have two sets of tests for my Rails application: rspec and cucumber. rspec heavily focusses on testing models and business logic while cucumber focusses on testing the entire application stack and user interaction. + +The problem is that as your app grows, your test set grows - and so does the time it takes to run those tests. + +_This post is inspired by [Corey Haines](http://coreyhaines.com)' talk at [Arrrrcamp](http://arrrrcamp.be) (Oct 2011) and my own experience with writing fast specs._ + +## Red - Green - Refactor + +If you do TDD/BDD you most likely follow the Red-Green-Refactor pattern: + +1. Write one test, and see it fail (red) +2. Write the most minimal implementation to satisfy that test, and see it pass (green) +3. Refactor your code to look/perform better (refactor) +4. Repeat + +But what if your test suite takes >30 seconds to run. You write a test, then wait 30 seconds to see the test fail. You then write the simple implementation, wait 30 seconds. Oops, you made a typo - fix it, wait 30 seconds. Now it passes. Refactor, again wait 30 seconds. + +I think this scenario is very familiar for many rails developers. + +## Take a closer look + +So, let's take a closer look at a real-world example. + +This is a `Post` model, it `belongs_to` and author and it can give you a summary of an article by returning the text above a '~' marker. + +``` ruby +# app/models/post.rb +class Post < ActiveRecord::Base + DELIMITER = "~\n" + + belongs_to :author + + def summary + summary = if body =~ /#{DELIMITER}/i + body.split(/#{DELIMITER}/i).first.strip + else + body + end + end +end +``` + +This is a spec that's defined for the `Post` model: + +``` ruby +# spec/models/post_spec.rb +require 'spec/helper' + +describe Post do + context "summary" do + it "should return the summary" do + post = FactoryGirl.build(:post, :body => "Summary\n~\nNo summary.") + post.summary.should == "Summary" + end + end +end +``` + +Running this spec would take at least 10 seconds. Running `time rspec spec/models/post_spec.rb` woudl output something like this: + +``` text +Finished in 0.05523 seconds +real 0m10.387s +``` + +This means that running the actual spec took 0.05s, but running the entire command took 10 seconds. What is slowing us down? + +## Dependencies + +As you see in the spec above I use `FactoryGirl.build` instead of `FactoryGirl.create` to prevent interacting with the database. I do this because hitting the database slows down your test. + +I removed the database dependency in order for my test to run faster. + +What other dependencies are there that could be removed in order to test the summary functionality? + +Any idea? + +Yes! + +Rails. + +## Rails is a dependency to your app + +You have a Rails-app. But Rails is not your app, it's a dependency, just like the `pg` and `haml` gems are dependencies. + +Loading the entire Rails stack takes quite some time. And just like with the database dependency we must ask ourselves: do we really need Rails to perform this test? + +There are a lot of scenarios where the answer to that question is _NO_. + +## Specs without Rails + +This may seem a bit weird at first, but let's take another look at the `Post` model: + +``` ruby +# app/models/post.rb +class Post < ActiveRecord::Base + DELIMITER = "~\n" + + belongs_to :author + + def summary + summary = if body =~ /#{DELIMITER}/i + body.split(/#{DELIMITER}/i).first.strip + else + body + end + end +end +``` + +The `summary` method does not interact with the `Post` model at all, except that it access the `body` attribute. But the `body` attribute is just a `String`. + +So, if we wanted to test the `summary` method and remove all Rails dependencies, we'd have to remove ActiveRecord. + +Consider this: + +``` ruby +# app/logic/myapp/summary.rb +module MyApp + class Summary + def self.for(text, delimiter) + summary = if text =~ /#{delimiter}/i + text.split(/#{delimiter}/i).first.strip + else + text + end + end + end +end +``` + +I think you can quickly see that this method does exactly the same as `Post#summary`. But it does not have any dependency to ActiveRecord. + +Could we rewrite our test for this new class? + + # fast_spec/myapp/summary_spec.rb + require 'myapp/summary' + + describe MyApp::Summary do + it "should return the summary" do + MyApp::Summary.for("Summary\n~\nNo summary.", "~\n").should == "Summary" + end + end + +That looks good! Note that this spec _does not_ include `spec_helper`. `spec_helper` is responsible for loading up your test environment, which normally includes all your app dependencies, including Rails. + +## Your new Post model + +The `Post` model should also be updated, of course to utilise this new class. + +``` ruby +# app/models/post.rb +class Post < ActiveRecord::Base + DELIMITER = "~\n" + + belongs_to :author + + def summary + MyApp::Summary.for(body, DELIMITER) + end +end +``` + +The spec for `Post` should also be changed. Since we already have tested that `MyApp::Summary#for` returns the right summary for a given text and delimiter, all we have left to do is make sure that `Post#summary` calls it correctly. + +``` ruby +# spec/models/post_spec.rb +require 'spec/helper' + +describe Post do + context "summary" do + it "should return the summary" do + post = FactoryGirl.build(:post) + MyApp::Summary.should_receive(:for).with(post.body, Post::DELIMITER) + post.summary + end + end +end +``` + +## Running fast specs + +The files above are located in `fast_spec` and `app/logic`. I do this because I want to separate my fast_specs so I can run them independtly from my normal specs. + +Running fast specs works like this: + +``` shell +rspec -I app/logic fast_spec +``` + +Try it out with `time rspec -I app/logic fast_spec`: + +``` text +Finished in 0.03223 seconds +real 0m0.421s +``` + +That's your same spec, down from about 10 seconds to 0.5 second. + +## The big picture + +By now you have seen that you can extract business logic into a seperate class. You've also seen that you can write tests that don't depend on Rails and run amazingly fast. + +Of course you ask, how does this relate to normal RSpec and Cucumber tests? + +My opinion is that your fast_specs test business logic that does not relate to anything Rails specific, like making calculations, processing text, et cetera. + +When you make changes to your business logic, you can test is very quickly. This shortens your TDD cycle and allows you to focus more on the task at hand (instead of waiting for your tests). + +RSpec tests are there to test integration with your dependencies like Rails. This is the place where test scopes and mailers. + +Cucumber still has its place to test user interaction with your app. Can a user still click the 'Order' button and get the proper response from our app. + +RSpec and Cucumber will now be ran less often. Maybe only before you commit code - or maybe have your CI run them for you? + +## Added benefit - Design + +An added bonus of TDD is that your tests dictate the design of your app. By using fast_spec you force your business logic into separate classes. This makes them even more re-usable than normal Rails models. + +Your ActiveRecord models now become cleaner and are more a _configuration of Rails_ than anything else. + +By doing this your app will become way more maintainable, easier to test, faster to test and your code will be more re-usable. What's not to like? + +## Where to go from here? + +As Corey Haines put it: + +> Try to extract one single method from your app into a fast_spec. Just one. When you have that one spec running so fast it's easy to add more. + +This would also be my advise to you. Try to extract one piece of functionality from a model into a fast_spec. It may be difficult at first, but try it and see the results. + +Then, when you have that one example working, add more. + diff --git a/content/posts/2011-10-14-rails-3-customized-exception-handling.md b/content/posts/2011/2011-10-14-rails-3-customized-exception-handling.md similarity index 96% rename from content/posts/2011-10-14-rails-3-customized-exception-handling.md rename to content/posts/2011/2011-10-14-rails-3-customized-exception-handling.md index a3bae48..ebaaa84 100644 --- a/content/posts/2011-10-14-rails-3-customized-exception-handling.md +++ b/content/posts/2011/2011-10-14-rails-3-customized-exception-handling.md @@ -1,100 +1,100 @@ -+++ -date = "2011-10-14" -title = "Rails 3: Customized exception handling" -tags = ["Rails", "rails3", "exceptions", "error", "rescue"] -slug = "rails-3-customized-exception-handling" -+++ -Exceptions happen. There's no way around that. But not all exceptions are created equally. - -For instance, a 404 "Not found" error can (and should) be handled correctly in your application. - -Let me give you an example of how to handle a `ActiveRecord::RecordNotFound` exception. Let's assume you have an application that could show a user profile: - -``` ruby -# GET /p/:name -def show - @profile = Profile.find(params[:name]) -end -``` - -Now, it may happen that the `:name` paramater contains a value that cannot be found in our database, most likely because someone made a typo in the URL. - -If `Profile#find` cannot get a proper result it will throw `ActiveRecord::RecordNotFound`. - -Now, instead of showing the user the (by default ugly) 404 page from `public/404.html` we want to do something more fancy. - -## Action-specific exception handling - -Here's one solution: - -``` ruby -# GET /p/:name -def show - @profile = Profile.find(params[:name]) -rescue - render :template => 'application/profile_not_found', :status => :not_found -end -``` - -You can now create `app/views/applicaiton/profile_not_found.html.haml` and give a nice custom error message to your user. - -You may try to find some matching profiles to `:name` or show a search box. - -## Global exception handling - -The above example only works for the specific profile `show` action. It's also possible to hanlde exceptions on the application level. - -Your `show` action still looks like this: - -``` ruby -# GET /p/:name -def show - @profile = Profile.find(params[:name]) -end -``` - -Then, in your `app/controllers/application_controller.rb` add this: - -``` ruby -class ApplicationController < ActionController::Base - rescue_from ActiveRecord::RecordNotFound, :with => :rescue_not_found - - protected - def rescue_not_found - render :template => 'application/not_found', :status => :not_found - end -end -``` - -Whenever an `ActiveRecord::RecordNotFound` exception is thrown (and not handled by the action itself), it will be handled by your `ApplicationController`. - -## Custom exceptions - -It's possible to throw your own custom exceptions and handle them in different ways. Like this: - -``` ruby -# Define your own error -class MyApp::ProfileNotFoundError < StandardError -end - -# GET /p/:name -def show - @profile = Profile.find_by_name(params[:name]) - raise MyApp::ProfileNotFoundError if @profile.nil? -end -``` - -And add this to your `ApplicationController`: - -``` ruby -rescue_from MyApp::ProfileNotFoundError, :with => :profile_not_found -``` - -Optionally, if you don't want to write that custom `profile_not_found` method, you may also supply a block: - -``` ruby -rescue_from MyApp::ProfileNotFoundError do |exception| - render :nothing => "Profile not found.", :status => 404 -end -``` - ++++ +date = "2011-10-14" +title = "Rails 3: Customized exception handling" +tags = ["Rails", "rails3", "exceptions", "error", "rescue"] +slug = "rails-3-customized-exception-handling" ++++ +Exceptions happen. There's no way around that. But not all exceptions are created equally. + +For instance, a 404 "Not found" error can (and should) be handled correctly in your application. + +Let me give you an example of how to handle a `ActiveRecord::RecordNotFound` exception. Let's assume you have an application that could show a user profile: + +``` ruby +# GET /p/:name +def show + @profile = Profile.find(params[:name]) +end +``` + +Now, it may happen that the `:name` paramater contains a value that cannot be found in our database, most likely because someone made a typo in the URL. + +If `Profile#find` cannot get a proper result it will throw `ActiveRecord::RecordNotFound`. + +Now, instead of showing the user the (by default ugly) 404 page from `public/404.html` we want to do something more fancy. + +## Action-specific exception handling + +Here's one solution: + +``` ruby +# GET /p/:name +def show + @profile = Profile.find(params[:name]) +rescue + render :template => 'application/profile_not_found', :status => :not_found +end +``` + +You can now create `app/views/applicaiton/profile_not_found.html.haml` and give a nice custom error message to your user. + +You may try to find some matching profiles to `:name` or show a search box. + +## Global exception handling + +The above example only works for the specific profile `show` action. It's also possible to hanlde exceptions on the application level. + +Your `show` action still looks like this: + +``` ruby +# GET /p/:name +def show + @profile = Profile.find(params[:name]) +end +``` + +Then, in your `app/controllers/application_controller.rb` add this: + +``` ruby +class ApplicationController < ActionController::Base + rescue_from ActiveRecord::RecordNotFound, :with => :rescue_not_found + + protected + def rescue_not_found + render :template => 'application/not_found', :status => :not_found + end +end +``` + +Whenever an `ActiveRecord::RecordNotFound` exception is thrown (and not handled by the action itself), it will be handled by your `ApplicationController`. + +## Custom exceptions + +It's possible to throw your own custom exceptions and handle them in different ways. Like this: + +``` ruby +# Define your own error +class MyApp::ProfileNotFoundError < StandardError +end + +# GET /p/:name +def show + @profile = Profile.find_by_name(params[:name]) + raise MyApp::ProfileNotFoundError if @profile.nil? +end +``` + +And add this to your `ApplicationController`: + +``` ruby +rescue_from MyApp::ProfileNotFoundError, :with => :profile_not_found +``` + +Optionally, if you don't want to write that custom `profile_not_found` method, you may also supply a block: + +``` ruby +rescue_from MyApp::ProfileNotFoundError do |exception| + render :nothing => "Profile not found.", :status => 404 +end +``` + diff --git a/content/posts/2011-10-22-automatically-switch-between-ssl-and-non-ssl-with-nginx-unicorn-rails.md b/content/posts/2011/2011-10-22-automatically-switch-between-ssl-and-non-ssl-with-nginx-unicorn-rails.md similarity index 97% rename from content/posts/2011-10-22-automatically-switch-between-ssl-and-non-ssl-with-nginx-unicorn-rails.md rename to content/posts/2011/2011-10-22-automatically-switch-between-ssl-and-non-ssl-with-nginx-unicorn-rails.md index 09ac21a..672ae30 100644 --- a/content/posts/2011-10-22-automatically-switch-between-ssl-and-non-ssl-with-nginx-unicorn-rails.md +++ b/content/posts/2011/2011-10-22-automatically-switch-between-ssl-and-non-ssl-with-nginx-unicorn-rails.md @@ -1,220 +1,220 @@ -+++ -date = "2011-10-22" -title = "Automatically switch between SSL and non-SSL with Nginx+Unicorn+Rails" -tags = ["Rails", "rails3", "unicorn", "nginx", "ssl"] -slug = "automatically-switch-between-ssl-and-non-ssl-with-nginx-unicorn-rails" -+++ - -_Scroll down for setup instructions. Or, read this bit about SSL in the real world first._ - -SSL or Secure Socket Layer is a nice way to secure sensitive parts of your Rails application. It achieves to goals. - -Firstly is encrypts all traffic between you and the remote server. Consider the passwords and personal information you submit to websites. When unencrypted (using HTTP), all this data is sent over the internet for all to read. With SSL (HTTPS) enabled, all traffic is encrypted, making it very hard for a third-party to eavesdrop. - -Secondly, a proper SSL connection can give you trust in that you're communicating with the right people. - -For example, Rabobank (a Dutch bank) uses SSL for its website. When you open their site, you'll notice the green 'Rabobank Nederland' in the address bar. - -![image](https://ariejannet.s3.amazonaws.com/content/rabobank-ssl.jpg) - -This tells me I am communicating with Rabobank Nederland. This is why SSL certificates are so expensive - the SSL authority needs to verify the identify of Rabobank before they issue the certificate. - -In the example above Rabobank uses an [EV SSL Certificate][evssl]. EV stands for Extended Validation. This means that the SSL authority has verified (among other things) that Rabobank is a legitimate business and that they are the legal owner of the domain rabobank.nl - -[evssl]: http://en.wikipedia.org/wiki/Extended_Validation_Certificate - -The cost for such an EV SSL Certificate is $200 - $1000 per year. You probably don't need it for your site. - -## SSL for you and me - -When you are looking to secure the back-end of your site (where you login etc.), you only require the encryption part of SSL. There are two routes you can take - -### Self signed SSL - -You are able to create a working SSL certificate yourself. This will give you encryption, but no identity validation. When you use a self-signed SSL certificate all browsers will warn you about this. - - * Encryption - * No validation - * Warnings from your browser - * Free - -For me, that's a reason not to use self signed SSL for any other than development and testing purposes. - -### Standard SSL - -Most SSL authorities provide you with a _Standard SSL_ product. These certificates only check if you own the domainname. They also offer encryption and work (without warnings) in your browser. You can get one of these for as little as $9 a year. - - * Encryption - * Domain validation / trust - * No warnings from your browser - * Cheap ($10 - $20) - -## Setting up SSL for your Rails application - -Setting up SSL is a web server thing. It does not involve your Rails appliation directly (but more on that in a moment). - -If you followed my [nginx+unicorn][nu] guide, you'll have Nginx and Unicorn setup already. - -[nu]: http://ariejan.net/2011/09/14/lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn - -### Create your private SSL key (key) - -First you need to create a private key. Do this on you server. The following command will generate a 2048 bit key. When it asks you to set a passphrase, do so. - -``` shell -$ openssl genrsa -des3 -out example.com.key 2048 -Generating RSA private key, 2048 bit long modulus -..................................+++ -.................................................................................+++ -e is 65537 (0x10001) -Enter pass phrase for example.com.key: -Verifying - Enter pass phrase for example.com.key: -``` - -### Creating a key and Certificate Sign Request (csr) - -Okay, you now have your key. Next step, create the Certificate Sign Request. The sign request is the part you'll send to the SSL authority to sign. You will need to provide some information here. Make sure you enter everything correctly. - - * `Country Name` - Your 2 letter country code. I.e. NL, UK, BE - * `State or Povince Name`. I.e. Noord-Brabant, New York - * `Locality Name` - Your city. I.e. Eindhoven, London - * `Organization Name` - Your company or site name: Ariejan.net, Apple Inc. - * `Organization Unit Name` - The section of your company. You may leave this blank. I.e. Online Services, Finance - * `Common Name` - The domain this SSL certificate will be used for. If you want to run this on https://www.example.com, you enter `www.example.com` here. This is *not* a wildcard. `example.com` will **not** work on `www.example.com` and vice versa. - * `Email Address`, `challenge password` and `optional company name` should normally be left blank. Just hit enter. - -Here's the full version: - -``` shell -$ openssl req -new -key example.com.key -out example.com.csr -Enter pass phrase for example.com.key: <> -You are about to be asked to enter information that will be incorporated -into your certificate request. -What you are about to enter is what is called a Distinguished Name or a DN. -There are quite a few fields but you can leave some blank -For some fields there will be a default value, -If you enter '.', the field will be left blank. ------ -Country Name (2 letter code) [AU]:NL -State or Province Name (full name) [Some-State]:Noord-Brabant -Locality Name (eg, city) []:Eindhoven -Organization Name (eg, company) [Internet Widgits Pty Ltd]:Ariejan.net -Organizational Unit Name (eg, section) []: -Common Name (eg, YOUR name) []:example.com -Email Address []: - -Please enter the following 'extra' attributes -to be sent with your certificate request -A challenge password []: -An optional company name []: -``` - -Great, you now have two files: - - * `example.com.key` - your private key. Keep it secret, keep it safe! - * `example.com.csr` - sign request - -### Get your certificate (crt) - -Now, go to your selected SSL authority, order your Standard SSL Certificate and upload the contents of `example.com.csr` when requested. - -After doing some validations, which may require you to click some links in emails, you're certificate should be ready for download. Save this file as `example.com.crt`. - -### Intermediate certificates - -Some SSL authorities work with so called intermediate certificates. This requires you to include an intermediate certificate with your own certificate. If your SSL provider requires this, save the intermediate certificate as `intermediate.crt`. - -For usage with nginx, you must place both your own and the intermediate certificates in a single file. This is easy: - -``` shell -cat example.com.crt intermediate.crt > sslchain.crt -``` - -### Remove the passphrase from your key - -Now, this is not recommended, but many people do this. The reason is that when your private key has passphrase, your server requires that passphrase everytime your (re)start it. This could mean that your server cannot boot up without manual interaction from your part. - -``` shell -cp example.com.key example.com.key.orig -openssl rsa -in example.com.key.orig -out example.com.key -``` - -You now have `example.com.key.orig`, which is your original private key _with_ the passphrase. And you have `example.com.key`, which is the same private key, but _without_ the passphrase. - -### Setup nginx for SSL - -Finally, you can setup Nginx for SSL. Normally I add both a SSL and non-SSL configuration. Setup is very easy. - -First of all, become root and copy your keys and certificate to `/etc/ssl`. - -``` shell -cp example.com.key example.com.crt /etc/ssl -``` - -or if you use an intermediate certificate: - -``` shell -cp example.com.key sslchain.crt /etc/ssl -``` - -Next, you take your non-SSL `server` configuration and duplicate it. Then you add the following lines. - -``` nginx -listen 443; # Instead of Listen 80 - -ssl on; -ssl_certificate /etc/ssl/sslchain.crt; # or /etc/ssl/example.com.crt -ssl_certificate_key /etc/ssl/example.com.key; - -location / { - # Add this to the location directive. - proxy_set_header X-Forwarded-Proto https; -} -``` - -Most of this is pretty straight forward. The `proxy_set_header` directive is needed to let your Rails application know if the request came in over SSL or not. Normally this shouldn't matter, but you'll need it for the next part of this guide. - -Save, restart nginx and your SSL connection should be available. - -## Automatically switch between SSL and non-SSL with Rails - -To take this site as an example, I don't want to run the front-end through SSL. First of all, you can't submit any data to my server. Second, I include several external resources (Disqus, Twitter, AdSense), that will give you warnings about using "insecure" content on an encrypted page. - -What I _do_ want is to encrypt traffic to the backend, where I log in and write posts like these. - -I need to make sure that your browser knows exactly when and when not to switch to SSL. This is where the `rack-ssl-enforcer` gem comes in. - -First, update your Gemfile: - -``` ruby -# Gemfile - gem 'rack-ssl-enforcer' -``` - -After you've run `bundle install`, update `config/application.rb` (or `config/environments/production.rb` is you only want to configure this for your production environment). - -``` ruby -# config/application.rb or config/environments/production.rb -config.middleware.use Rack::SslEnforcer, - :redirect_to => 'https://example.com', # For when behind a proxy, like nginx - :only => [/^\/admin\//, /^\/authors\//], # Force SSL on everything behind /admin and /authors - :strict => true # Force no-SSL for everything else -``` - -With the following statement, you achieve the following: - - * When you access any URL with a path that starts with `/admin` or `/authors`, you'll be redirected to the SSL site. - * Because we're behind a proxy and want to do proper redirects, we specify the correct SSL domain. - * We set `strict` to true. If you access something that is _not_ `/admin` or `/authors`, you will be redirected to the non-SSL version of that page. - -There's a lot more possible with the [rack-ssl-enforcer][rse] gem. Checkout their [README on Github][readme] for details. - -_Note: if you find yourself getting into an infinite redirect loop, make sure have the `proxy_set_header` directive set correctly in your Nginx configuration._ - -[rse]: http://rubygems.org/gems/rack-ssl-enforcer -[readme]: https://github.com/tobmatth/rack-ssl-enforcer#readme - -## Wrapping up - -You now know how you can setup an SSL certificate with Nginx and how you can make your Rails application automatically switch between SSL and non-SSL whenever you want to. - ++++ +date = "2011-10-22" +title = "Automatically switch between SSL and non-SSL with Nginx+Unicorn+Rails" +tags = ["Rails", "rails3", "unicorn", "nginx", "ssl"] +slug = "automatically-switch-between-ssl-and-non-ssl-with-nginx-unicorn-rails" ++++ + +_Scroll down for setup instructions. Or, read this bit about SSL in the real world first._ + +SSL or Secure Socket Layer is a nice way to secure sensitive parts of your Rails application. It achieves to goals. + +Firstly is encrypts all traffic between you and the remote server. Consider the passwords and personal information you submit to websites. When unencrypted (using HTTP), all this data is sent over the internet for all to read. With SSL (HTTPS) enabled, all traffic is encrypted, making it very hard for a third-party to eavesdrop. + +Secondly, a proper SSL connection can give you trust in that you're communicating with the right people. + +For example, Rabobank (a Dutch bank) uses SSL for its website. When you open their site, you'll notice the green 'Rabobank Nederland' in the address bar. + +![image](https://ariejannet.s3.amazonaws.com/content/rabobank-ssl.jpg) + +This tells me I am communicating with Rabobank Nederland. This is why SSL certificates are so expensive - the SSL authority needs to verify the identify of Rabobank before they issue the certificate. + +In the example above Rabobank uses an [EV SSL Certificate][evssl]. EV stands for Extended Validation. This means that the SSL authority has verified (among other things) that Rabobank is a legitimate business and that they are the legal owner of the domain rabobank.nl + +[evssl]: http://en.wikipedia.org/wiki/Extended_Validation_Certificate + +The cost for such an EV SSL Certificate is $200 - $1000 per year. You probably don't need it for your site. + +## SSL for you and me + +When you are looking to secure the back-end of your site (where you login etc.), you only require the encryption part of SSL. There are two routes you can take + +### Self signed SSL + +You are able to create a working SSL certificate yourself. This will give you encryption, but no identity validation. When you use a self-signed SSL certificate all browsers will warn you about this. + + * Encryption + * No validation + * Warnings from your browser + * Free + +For me, that's a reason not to use self signed SSL for any other than development and testing purposes. + +### Standard SSL + +Most SSL authorities provide you with a _Standard SSL_ product. These certificates only check if you own the domainname. They also offer encryption and work (without warnings) in your browser. You can get one of these for as little as $9 a year. + + * Encryption + * Domain validation / trust + * No warnings from your browser + * Cheap ($10 - $20) + +## Setting up SSL for your Rails application + +Setting up SSL is a web server thing. It does not involve your Rails appliation directly (but more on that in a moment). + +If you followed my [nginx+unicorn][nu] guide, you'll have Nginx and Unicorn setup already. + +[nu]: http://ariejan.net/2011/09/14/lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn + +### Create your private SSL key (key) + +First you need to create a private key. Do this on you server. The following command will generate a 2048 bit key. When it asks you to set a passphrase, do so. + +``` shell +$ openssl genrsa -des3 -out example.com.key 2048 +Generating RSA private key, 2048 bit long modulus +..................................+++ +.................................................................................+++ +e is 65537 (0x10001) +Enter pass phrase for example.com.key: +Verifying - Enter pass phrase for example.com.key: +``` + +### Creating a key and Certificate Sign Request (csr) + +Okay, you now have your key. Next step, create the Certificate Sign Request. The sign request is the part you'll send to the SSL authority to sign. You will need to provide some information here. Make sure you enter everything correctly. + + * `Country Name` - Your 2 letter country code. I.e. NL, UK, BE + * `State or Povince Name`. I.e. Noord-Brabant, New York + * `Locality Name` - Your city. I.e. Eindhoven, London + * `Organization Name` - Your company or site name: Ariejan.net, Apple Inc. + * `Organization Unit Name` - The section of your company. You may leave this blank. I.e. Online Services, Finance + * `Common Name` - The domain this SSL certificate will be used for. If you want to run this on https://www.example.com, you enter `www.example.com` here. This is *not* a wildcard. `example.com` will **not** work on `www.example.com` and vice versa. + * `Email Address`, `challenge password` and `optional company name` should normally be left blank. Just hit enter. + +Here's the full version: + +``` shell +$ openssl req -new -key example.com.key -out example.com.csr +Enter pass phrase for example.com.key: <> +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +----- +Country Name (2 letter code) [AU]:NL +State or Province Name (full name) [Some-State]:Noord-Brabant +Locality Name (eg, city) []:Eindhoven +Organization Name (eg, company) [Internet Widgits Pty Ltd]:Ariejan.net +Organizational Unit Name (eg, section) []: +Common Name (eg, YOUR name) []:example.com +Email Address []: + +Please enter the following 'extra' attributes +to be sent with your certificate request +A challenge password []: +An optional company name []: +``` + +Great, you now have two files: + + * `example.com.key` - your private key. Keep it secret, keep it safe! + * `example.com.csr` - sign request + +### Get your certificate (crt) + +Now, go to your selected SSL authority, order your Standard SSL Certificate and upload the contents of `example.com.csr` when requested. + +After doing some validations, which may require you to click some links in emails, you're certificate should be ready for download. Save this file as `example.com.crt`. + +### Intermediate certificates + +Some SSL authorities work with so called intermediate certificates. This requires you to include an intermediate certificate with your own certificate. If your SSL provider requires this, save the intermediate certificate as `intermediate.crt`. + +For usage with nginx, you must place both your own and the intermediate certificates in a single file. This is easy: + +``` shell +cat example.com.crt intermediate.crt > sslchain.crt +``` + +### Remove the passphrase from your key + +Now, this is not recommended, but many people do this. The reason is that when your private key has passphrase, your server requires that passphrase everytime your (re)start it. This could mean that your server cannot boot up without manual interaction from your part. + +``` shell +cp example.com.key example.com.key.orig +openssl rsa -in example.com.key.orig -out example.com.key +``` + +You now have `example.com.key.orig`, which is your original private key _with_ the passphrase. And you have `example.com.key`, which is the same private key, but _without_ the passphrase. + +### Setup nginx for SSL + +Finally, you can setup Nginx for SSL. Normally I add both a SSL and non-SSL configuration. Setup is very easy. + +First of all, become root and copy your keys and certificate to `/etc/ssl`. + +``` shell +cp example.com.key example.com.crt /etc/ssl +``` + +or if you use an intermediate certificate: + +``` shell +cp example.com.key sslchain.crt /etc/ssl +``` + +Next, you take your non-SSL `server` configuration and duplicate it. Then you add the following lines. + +``` nginx +listen 443; # Instead of Listen 80 + +ssl on; +ssl_certificate /etc/ssl/sslchain.crt; # or /etc/ssl/example.com.crt +ssl_certificate_key /etc/ssl/example.com.key; + +location / { + # Add this to the location directive. + proxy_set_header X-Forwarded-Proto https; +} +``` + +Most of this is pretty straight forward. The `proxy_set_header` directive is needed to let your Rails application know if the request came in over SSL or not. Normally this shouldn't matter, but you'll need it for the next part of this guide. + +Save, restart nginx and your SSL connection should be available. + +## Automatically switch between SSL and non-SSL with Rails + +To take this site as an example, I don't want to run the front-end through SSL. First of all, you can't submit any data to my server. Second, I include several external resources (Disqus, Twitter, AdSense), that will give you warnings about using "insecure" content on an encrypted page. + +What I _do_ want is to encrypt traffic to the backend, where I log in and write posts like these. + +I need to make sure that your browser knows exactly when and when not to switch to SSL. This is where the `rack-ssl-enforcer` gem comes in. + +First, update your Gemfile: + +``` ruby +# Gemfile + gem 'rack-ssl-enforcer' +``` + +After you've run `bundle install`, update `config/application.rb` (or `config/environments/production.rb` is you only want to configure this for your production environment). + +``` ruby +# config/application.rb or config/environments/production.rb +config.middleware.use Rack::SslEnforcer, + :redirect_to => 'https://example.com', # For when behind a proxy, like nginx + :only => [/^\/admin\//, /^\/authors\//], # Force SSL on everything behind /admin and /authors + :strict => true # Force no-SSL for everything else +``` + +With the following statement, you achieve the following: + + * When you access any URL with a path that starts with `/admin` or `/authors`, you'll be redirected to the SSL site. + * Because we're behind a proxy and want to do proper redirects, we specify the correct SSL domain. + * We set `strict` to true. If you access something that is _not_ `/admin` or `/authors`, you will be redirected to the non-SSL version of that page. + +There's a lot more possible with the [rack-ssl-enforcer][rse] gem. Checkout their [README on Github][readme] for details. + +_Note: if you find yourself getting into an infinite redirect loop, make sure have the `proxy_set_header` directive set correctly in your Nginx configuration._ + +[rse]: http://rubygems.org/gems/rack-ssl-enforcer +[readme]: https://github.com/tobmatth/rack-ssl-enforcer#readme + +## Wrapping up + +You now know how you can setup an SSL certificate with Nginx and how you can make your Rails application automatically switch between SSL and non-SSL whenever you want to. + diff --git a/content/posts/2011-10-24-installing-node-js-and-npm-on-ubuntu-debian.md b/content/posts/2011/2011-10-24-installing-node-js-and-npm-on-ubuntu-debian.md similarity index 100% rename from content/posts/2011-10-24-installing-node-js-and-npm-on-ubuntu-debian.md rename to content/posts/2011/2011-10-24-installing-node-js-and-npm-on-ubuntu-debian.md diff --git a/content/posts/2011-11-08-fixing-a-slow-starting-terminal-or-iterm2-on-mac-os-x.md b/content/posts/2011/2011-11-08-fixing-a-slow-starting-terminal-or-iterm2-on-mac-os-x.md similarity index 100% rename from content/posts/2011-11-08-fixing-a-slow-starting-terminal-or-iterm2-on-mac-os-x.md rename to content/posts/2011/2011-11-08-fixing-a-slow-starting-terminal-or-iterm2-on-mac-os-x.md diff --git a/content/posts/2011-11-09-contributing-to-open-source-with-github.md b/content/posts/2011/2011-11-09-contributing-to-open-source-with-github.md similarity index 97% rename from content/posts/2011-11-09-contributing-to-open-source-with-github.md rename to content/posts/2011/2011-11-09-contributing-to-open-source-with-github.md index f882816..6016194 100644 --- a/content/posts/2011-11-09-contributing-to-open-source-with-github.md +++ b/content/posts/2011/2011-11-09-contributing-to-open-source-with-github.md @@ -1,87 +1,87 @@ -+++ -date = "2011-11-09" -title = "Contributing to Open-Source with Github" -tags = ["git", "rebase", "github", "flow", "fork", "upstream"] -slug = "contributing-to-open-source-with-github" -+++ -You want to contribute to an open-source project, but are scared away by all the git-complexity involved? This small guide will help you out. - -Octocat - -## Step 1 - Fork, fork, fork - -First create a fork of the original project. You can do this easily by clicking the "Fork" button on the top of the Github project page. This will give you your own copy (fork) of the entire repository. - -Then, check out your fork: - -``` shell -git clone git@github.com:ariejan/repo-name.git -``` - -## Step 2 - Contribute - -Before you start writing code there are a few tasks you need to perform: - - * Are there tests for this project? Are they all green? If not, fix this first. (using this same step, of course) - * Create a new branch: `git checkout -b fix_for_this_or_that` - * Red-Green-Refactor (e.g. write code) - * Commit your changes (in your `fix_for_this_or_that` branch). - -## Step 3 - Sharing your contribution - -With your contribution done, don't merge it back into `master`. `master` is your way of receiving changes from the original (upstream) repo (see step 4). - -First push your branch to Github, so you can share it with others. - -``` shell -git push origin fix_for_this_or_that -``` - -You should now see this branch in your Github project page. You'll also notice there's a "Pull Request" button at the top. Click it if you want the project maintainer to pull your `fix_for_this_or_that` branch into the main project. - -## Step 4 - Keeping up-to-date - -Over time the `master` of your fork will start lagging behind. Because you did not merge any of your code changes into the `master` of your fork, you can update it easily. - -Before you can pull in changes you must add a git remote for it. You can use the _Git Read-only_ URL for this. - -``` shell -git remote add upstream https://github.com/some_one/some-repo.git -``` - -Now, for raking in the changes; - -``` shell -git checkout master -git fetch upstream -git merge upstream/master -``` - -## Step 4.5 - Keeping your feature branch up-to-date - -If you pulled in changes from `upstream` and did not yet share your feature branch, you can rebase your feature branch. This makes sure you have the latest code from `master`. This also makes merging your pull request easier. - -

Do not rebase if you already pushed your branch to Github. Read why.

- -``` shell -git checkout fix_for_this_or_that -git rebase master -``` - -If any conflict arise, fix them. And continue your rebase: - -``` shell -git add conflicting_file -git rebase --continue -``` - -You may also abort the rebase: - -``` shell -git rebase --abort -``` - -## Big picture - -This small guide will help you to fork repositories on Github and use them to contribute code. By using the approach you lighten the task of the project maintainer who can easily checkout your specific changes and decide to include them into the main project or not. - ++++ +date = "2011-11-09" +title = "Contributing to Open-Source with Github" +tags = ["git", "rebase", "github", "flow", "fork", "upstream"] +slug = "contributing-to-open-source-with-github" ++++ +You want to contribute to an open-source project, but are scared away by all the git-complexity involved? This small guide will help you out. + +Octocat + +## Step 1 - Fork, fork, fork + +First create a fork of the original project. You can do this easily by clicking the "Fork" button on the top of the Github project page. This will give you your own copy (fork) of the entire repository. + +Then, check out your fork: + +``` shell +git clone git@github.com:ariejan/repo-name.git +``` + +## Step 2 - Contribute + +Before you start writing code there are a few tasks you need to perform: + + * Are there tests for this project? Are they all green? If not, fix this first. (using this same step, of course) + * Create a new branch: `git checkout -b fix_for_this_or_that` + * Red-Green-Refactor (e.g. write code) + * Commit your changes (in your `fix_for_this_or_that` branch). + +## Step 3 - Sharing your contribution + +With your contribution done, don't merge it back into `master`. `master` is your way of receiving changes from the original (upstream) repo (see step 4). + +First push your branch to Github, so you can share it with others. + +``` shell +git push origin fix_for_this_or_that +``` + +You should now see this branch in your Github project page. You'll also notice there's a "Pull Request" button at the top. Click it if you want the project maintainer to pull your `fix_for_this_or_that` branch into the main project. + +## Step 4 - Keeping up-to-date + +Over time the `master` of your fork will start lagging behind. Because you did not merge any of your code changes into the `master` of your fork, you can update it easily. + +Before you can pull in changes you must add a git remote for it. You can use the _Git Read-only_ URL for this. + +``` shell +git remote add upstream https://github.com/some_one/some-repo.git +``` + +Now, for raking in the changes; + +``` shell +git checkout master +git fetch upstream +git merge upstream/master +``` + +## Step 4.5 - Keeping your feature branch up-to-date + +If you pulled in changes from `upstream` and did not yet share your feature branch, you can rebase your feature branch. This makes sure you have the latest code from `master`. This also makes merging your pull request easier. + +

Do not rebase if you already pushed your branch to Github. Read why.

+ +``` shell +git checkout fix_for_this_or_that +git rebase master +``` + +If any conflict arise, fix them. And continue your rebase: + +``` shell +git add conflicting_file +git rebase --continue +``` + +You may also abort the rebase: + +``` shell +git rebase --abort +``` + +## Big picture + +This small guide will help you to fork repositories on Github and use them to contribute code. By using the approach you lighten the task of the project maintainer who can easily checkout your specific changes and decide to include them into the main project or not. + diff --git a/content/posts/2011-11-18-deploying-a-third-party-rails-application-like-gitlab.md b/content/posts/2011/2011-11-18-deploying-a-third-party-rails-application-like-gitlab.md similarity index 97% rename from content/posts/2011-11-18-deploying-a-third-party-rails-application-like-gitlab.md rename to content/posts/2011/2011-11-18-deploying-a-third-party-rails-application-like-gitlab.md index ac36597..4c854e1 100644 --- a/content/posts/2011-11-18-deploying-a-third-party-rails-application-like-gitlab.md +++ b/content/posts/2011/2011-11-18-deploying-a-third-party-rails-application-like-gitlab.md @@ -1,75 +1,75 @@ -+++ -date = "2011-11-18" -title = "Deploying a third-party Rails application - like Gitlab" -tags = ["Capistrano", "github", "gitlab", "deploy"] -slug = "deploying-a-third-party-rails-application-like-gitlab" -+++ -We all know how to deploy our own Rails projects. (If not, [read this guide][1].) But how do you handle deploying a third-party application that may require some customisation on your part? - -A good example would be [Gitlab][gitlab] - -Gitlab is an open source Github clone, build using Ruby on Rails. It's a nice project that uses Gitosis under the hood to manage your git repositories. There are [several][2] [good][3] installation guides available on the web, but they all assume you want to deploy gitlab verbatim - without any modification or configuration - -I have also setup Gitlab, but I want to use capistrano and unicorn. I also want to tweak some configuration. In some rare cases I want to fix an annoying bug and not wait for the Gitlab team to pull it. - -Doing a `git pull` on my remote server just won't cut it. - -## Fork! Fork! - -What I did was clone Gitlab and use the same principles describe in my [_Contributing to open source with Github_][4] to apply my own changes and merge any upstream changes when they are available. - -Here's how I set everything up. - -First, clone the official Gitlab repository and name it `upstream`. - -``` shell -git clone --origin upstream https://github.com/gitlabhq/gitlabhq.git my_git_server -``` - -Next I made all the changes I want. I updated `config/gitosis.yml` and `unicorn` to `Gemfile` and setup Capistrano. - -I then pushed this to my own git server. This is the same server Capistrano will use to pull changes from. - -``` shell -git remote add origin git@git.ariejan.net:my_git_server.git -git push origin master -cap deploy -``` - -That's all there is to deploying Gitlab from my own repository. - -## Merging upstream changes - -Now, the Gitlab crew is pushing out new features at an amazing rate. So, how do I get those new features (and the occasional bug fix) into my copy of Gitlab for deploying? - -``` shell -git fetch upstream -``` - -Remember how we named the official Gitlab repository `upstream` earlier? With this `fetch` we get all changes from their repository (but we don't apply them to anything yet). - -Then, merge the upstream changes with your own branch. - -``` shell -git merge upstream/master -``` - -There may be merge conflicts, just resolve them and commit your merge. Then again to deploy: - -``` shell -git push origin master -cap deploy -``` - -## Why do this? - -The reason I use this approach is that it's easy to merge upstream changes and have my own customizations and deployment tools at the same time. - -[1]: http://ariejan.net/2011/09/14/lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn -[gitlab]: http://www.gitlabhq.com -[2]: http://www.ryanwersal.com/blog/2011/10/18/installing-gitlab-on-ubuntu-server/ -[3]: http://nepalonrails.tumblr.com/post/12603081685/setup-gitlab-github-clone-using-vagrant-and-chef -[4]: http://ariejan.net/2011/11/09/contributing-to-open-source-with-github - - - ++++ +date = "2011-11-18" +title = "Deploying a third-party Rails application - like Gitlab" +tags = ["Capistrano", "github", "gitlab", "deploy"] +slug = "deploying-a-third-party-rails-application-like-gitlab" ++++ +We all know how to deploy our own Rails projects. (If not, [read this guide][1].) But how do you handle deploying a third-party application that may require some customisation on your part? + +A good example would be [Gitlab][gitlab] + +Gitlab is an open source Github clone, build using Ruby on Rails. It's a nice project that uses Gitosis under the hood to manage your git repositories. There are [several][2] [good][3] installation guides available on the web, but they all assume you want to deploy gitlab verbatim - without any modification or configuration + +I have also setup Gitlab, but I want to use capistrano and unicorn. I also want to tweak some configuration. In some rare cases I want to fix an annoying bug and not wait for the Gitlab team to pull it. + +Doing a `git pull` on my remote server just won't cut it. + +## Fork! Fork! + +What I did was clone Gitlab and use the same principles describe in my [_Contributing to open source with Github_][4] to apply my own changes and merge any upstream changes when they are available. + +Here's how I set everything up. + +First, clone the official Gitlab repository and name it `upstream`. + +``` shell +git clone --origin upstream https://github.com/gitlabhq/gitlabhq.git my_git_server +``` + +Next I made all the changes I want. I updated `config/gitosis.yml` and `unicorn` to `Gemfile` and setup Capistrano. + +I then pushed this to my own git server. This is the same server Capistrano will use to pull changes from. + +``` shell +git remote add origin git@git.ariejan.net:my_git_server.git +git push origin master +cap deploy +``` + +That's all there is to deploying Gitlab from my own repository. + +## Merging upstream changes + +Now, the Gitlab crew is pushing out new features at an amazing rate. So, how do I get those new features (and the occasional bug fix) into my copy of Gitlab for deploying? + +``` shell +git fetch upstream +``` + +Remember how we named the official Gitlab repository `upstream` earlier? With this `fetch` we get all changes from their repository (but we don't apply them to anything yet). + +Then, merge the upstream changes with your own branch. + +``` shell +git merge upstream/master +``` + +There may be merge conflicts, just resolve them and commit your merge. Then again to deploy: + +``` shell +git push origin master +cap deploy +``` + +## Why do this? + +The reason I use this approach is that it's easy to merge upstream changes and have my own customizations and deployment tools at the same time. + +[1]: http://ariejan.net/2011/09/14/lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn +[gitlab]: http://www.gitlabhq.com +[2]: http://www.ryanwersal.com/blog/2011/10/18/installing-gitlab-on-ubuntu-server/ +[3]: http://nepalonrails.tumblr.com/post/12603081685/setup-gitlab-github-clone-using-vagrant-and-chef +[4]: http://ariejan.net/2011/11/09/contributing-to-open-source-with-github + + + diff --git a/content/posts/2011-11-22-upgrade-postgresql-8-4-to-postgresql-9-1-on-debian.md b/content/posts/2011/2011-11-22-upgrade-postgresql-8-4-to-postgresql-9-1-on-debian.md similarity index 96% rename from content/posts/2011-11-22-upgrade-postgresql-8-4-to-postgresql-9-1-on-debian.md rename to content/posts/2011/2011-11-22-upgrade-postgresql-8-4-to-postgresql-9-1-on-debian.md index dce51d4..02aac9b 100644 --- a/content/posts/2011-11-22-upgrade-postgresql-8-4-to-postgresql-9-1-on-debian.md +++ b/content/posts/2011/2011-11-22-upgrade-postgresql-8-4-to-postgresql-9-1-on-debian.md @@ -1,35 +1,35 @@ -+++ -date = "2011-11-22" -title = "Upgrade postgresql-8.4 to postgresql-9.1 on debian" -tags = ["Ubuntu", "debian", "dba", "postgres", "postgresql"] -slug = "upgrade-postgresql-8-4-to-postgresql-9-1-on-debian" -+++ -Today I upgraded a production PostgreSQL 8.4 database to version 9.1. This was on a Debian server. -~ -The first step is to make a full dump of your data. I personally like to store that dump somewhere safe before upgrading. As root: - -``` shell -su - postgres -pg_dumpall > dump.sql -exit -cp ~postgres/dump.sql /root/ -``` - -Now you can safely remove the postgresql-8.4 and install postgresql-9.1: - -``` shell -aptitude purge postgresql-8.4 -aptitude install postgresql-9.1 -``` - -Next check the postgresql configuration in `/etc/postgresql/9.1/main`. If you make any changes, make sure to restart postgres with `/etc/init.d/postgresql restart`. - -Postgresql 9.1 is now up and running, let's import our data back into it. - -``` shell -su - postgres -psql < dump.sql -``` - -That's all. You're now fully upgraded to PostgreSQL 9.1. - ++++ +date = "2011-11-22" +title = "Upgrade postgresql-8.4 to postgresql-9.1 on debian" +tags = ["Ubuntu", "debian", "dba", "postgres", "postgresql"] +slug = "upgrade-postgresql-8-4-to-postgresql-9-1-on-debian" ++++ +Today I upgraded a production PostgreSQL 8.4 database to version 9.1. This was on a Debian server. +~ +The first step is to make a full dump of your data. I personally like to store that dump somewhere safe before upgrading. As root: + +``` shell +su - postgres +pg_dumpall > dump.sql +exit +cp ~postgres/dump.sql /root/ +``` + +Now you can safely remove the postgresql-8.4 and install postgresql-9.1: + +``` shell +aptitude purge postgresql-8.4 +aptitude install postgresql-9.1 +``` + +Next check the postgresql configuration in `/etc/postgresql/9.1/main`. If you make any changes, make sure to restart postgres with `/etc/init.d/postgresql restart`. + +Postgresql 9.1 is now up and running, let's import our data back into it. + +``` shell +su - postgres +psql < dump.sql +``` + +That's all. You're now fully upgraded to PostgreSQL 9.1. + diff --git a/content/posts/2011-12-13-recursively-fixing-file-and-directory-permissions.md b/content/posts/2011/2011-12-13-recursively-fixing-file-and-directory-permissions.md similarity index 97% rename from content/posts/2011-12-13-recursively-fixing-file-and-directory-permissions.md rename to content/posts/2011/2011-12-13-recursively-fixing-file-and-directory-permissions.md index 4c16bf2..5082f2d 100644 --- a/content/posts/2011-12-13-recursively-fixing-file-and-directory-permissions.md +++ b/content/posts/2011/2011-12-13-recursively-fixing-file-and-directory-permissions.md @@ -1,28 +1,28 @@ -+++ -date = "2011-12-13" -title = "Recursively fixing file and directory permissions" -tags = ["Linux", "BASH", "git", "sh", "file permissions"] -slug = "recursively-fixing-file-and-directory-permissions" -+++ -While working on a [Gitlab][1] installation I noticed that all repository file permissions were off. Fixing recursive file and directory permissions can be quite hard. Or so I thought. - -Using the following commands (in plain Bash) allow you to recursively set permissions for files and directories. So, to fix the proper read permissions on your Gitlab repositories you can use this: - -``` shell -# Go to your git repositories directory (as git or the gitlab user) -cd /home/git/repositories - -# Fix ownership -sudo chown -R git:git * - -# Fix directory permissions -sudo find -type d -exec chmod 770 {} \; - -# Fix file permissions -sudo find -type f -exec chmod 660 {} \; -``` - -After this, your Gitlab should have no trouble accessing your code (e.g. in the tree browser). - -[1]: http://gitlabhq.com/ - ++++ +date = "2011-12-13" +title = "Recursively fixing file and directory permissions" +tags = ["Linux", "BASH", "git", "sh", "file permissions"] +slug = "recursively-fixing-file-and-directory-permissions" ++++ +While working on a [Gitlab][1] installation I noticed that all repository file permissions were off. Fixing recursive file and directory permissions can be quite hard. Or so I thought. + +Using the following commands (in plain Bash) allow you to recursively set permissions for files and directories. So, to fix the proper read permissions on your Gitlab repositories you can use this: + +``` shell +# Go to your git repositories directory (as git or the gitlab user) +cd /home/git/repositories + +# Fix ownership +sudo chown -R git:git * + +# Fix directory permissions +sudo find -type d -exec chmod 770 {} \; + +# Fix file permissions +sudo find -type f -exec chmod 660 {} \; +``` + +After this, your Gitlab should have no trouble accessing your code (e.g. in the tree browser). + +[1]: http://gitlabhq.com/ + diff --git a/content/posts/2012-01-10-removing-untracked-files-and-directories-with-git.md b/content/posts/2012/2012-01-10-removing-untracked-files-and-directories-with-git.md similarity index 98% rename from content/posts/2012-01-10-removing-untracked-files-and-directories-with-git.md rename to content/posts/2012/2012-01-10-removing-untracked-files-and-directories-with-git.md index 55307d3..4a583a4 100644 --- a/content/posts/2012-01-10-removing-untracked-files-and-directories-with-git.md +++ b/content/posts/2012/2012-01-10-removing-untracked-files-and-directories-with-git.md @@ -4,47 +4,47 @@ title = "Removing untracked files and directories with git" tags = ["git"] slug = "removing-untracked-files-and-directories-with-git" +++ -I just tried writing some new code, but it was no success. This happens, but it left me with a working copy littered with new and changed files. - - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: config/routes.rb - # - # Untracked files: - # (use "git add ..." to include in what will be committed) - # - # db/migrate/20111231131752_create_validations.rb - # vendor/assets/images/ - # vendor/assets/javascripts/ - # vendor/assets/stylesheets/custom.sass - -So, how do I get rid of this mess? - -## 1 - Be absolutely sure you want to delete your work -I sometimes commit my work although it's of no use to me at the moment. It's in a separate branch anyway and can be easily ignored until I come back to it. - -So, if you're really sure you want to delete your changes and files, continue to step 2. - -## 2 - Delete untracked files and directories -Now, delete all files that are not yet tracked by git. You could do it like this: - - rm -r db/migrate/20111231131752_create_validations.rb vendor/assets/images \ - vendor/assets/javascripts/ vendor/assets/stylesheets/custom.sass - -This requires you to copy/paste or type all the files and directories you want to delete. There's a much easier way: ask git to do it for you: - - git clean -df - -The `d` option tells git to include directories, `f` says that you really want to perform the delete. Optionally, you can first run with `n` instead of `f` to see what's going to happen - a so called dry-run. - -If you use this command frequently and don't want to specify the `f` options every time you can set `clean.requireForce` in your `~/.gitconfig` to `true` to omit the `f` options. - -## 3 - Reset changes to tracked files -With all the new stuff out of the way, let's clean up the files that are tracked by git. You want to revert everything back to the last commit you made: - - git reset HEAD --hard - +I just tried writing some new code, but it was no success. This happens, but it left me with a working copy littered with new and changed files. + + # Changes not staged for commit: + # (use "git add ..." to update what will be committed) + # (use "git checkout -- ..." to discard changes in working directory) + # + # modified: config/routes.rb + # + # Untracked files: + # (use "git add ..." to include in what will be committed) + # + # db/migrate/20111231131752_create_validations.rb + # vendor/assets/images/ + # vendor/assets/javascripts/ + # vendor/assets/stylesheets/custom.sass + +So, how do I get rid of this mess? + +## 1 - Be absolutely sure you want to delete your work +I sometimes commit my work although it's of no use to me at the moment. It's in a separate branch anyway and can be easily ignored until I come back to it. + +So, if you're really sure you want to delete your changes and files, continue to step 2. + +## 2 - Delete untracked files and directories +Now, delete all files that are not yet tracked by git. You could do it like this: + + rm -r db/migrate/20111231131752_create_validations.rb vendor/assets/images \ + vendor/assets/javascripts/ vendor/assets/stylesheets/custom.sass + +This requires you to copy/paste or type all the files and directories you want to delete. There's a much easier way: ask git to do it for you: + + git clean -df + +The `d` option tells git to include directories, `f` says that you really want to perform the delete. Optionally, you can first run with `n` instead of `f` to see what's going to happen - a so called dry-run. + +If you use this command frequently and don't want to specify the `f` options every time you can set `clean.requireForce` in your `~/.gitconfig` to `true` to omit the `f` options. + +## 3 - Reset changes to tracked files +With all the new stuff out of the way, let's clean up the files that are tracked by git. You want to revert everything back to the last commit you made: + + git reset HEAD --hard + That's all. You're now back to a clean working directory at `HEAD`. Start over now. diff --git a/content/posts/2012-03-20-open-source-is-a-privilege-not-a-right.md b/content/posts/2012/2012-03-20-open-source-is-a-privilege-not-a-right.md similarity index 98% rename from content/posts/2012-03-20-open-source-is-a-privilege-not-a-right.md rename to content/posts/2012/2012-03-20-open-source-is-a-privilege-not-a-right.md index fafcd5f..ca0a8c1 100644 --- a/content/posts/2012-03-20-open-source-is-a-privilege-not-a-right.md +++ b/content/posts/2012/2012-03-20-open-source-is-a-privilege-not-a-right.md @@ -4,53 +4,53 @@ title = "Open Source is a privilege. Not a right." tags = ["oss", "free", "open-source"] slug = "open-source-is-a-privilege-not-a-right" +++ -_Edit: this is not a Gitlab specific issue. I've seen it before and I'm seeing it again at the Gitlab project._ - -The past few months I've been contributing to the [Gitlab](https://github.com/gitlabhq/gitlabhq) project. This has been a great experience, mostly because Gitlab has become a very popular project with over 2.3k watchers right now. - -It gives me great satisfaction knowing that my code is being used by hundreds if not thousands of people right now. But there is also this little thing that has been bugging me lately. - -There is a small core team of developers devoting time to the development of Gitlab. They do this passionatly and they have been cranking out releases and new features every 22nd of month for the past six months. - -A lot of effort has gone into making Gitlab what it is today. - -But with the rise in popularity there has also been an increased number issues, bugs and feature requests. The mailing list is also more active than ever. Of course, all of this is a good thing for an open source project, you would think. - -Most users appreciate the effort that goes into developing an application as complex as Gitlab. They appreciate the fact it's available for _free_. The appreciate somebody made time to develop a tool they can put to use on a daily basis. - -This appreciation is great motivator for the developers. Knowing their code is being put to good use only drives them write more code, more features. - -Unfortunately, I read tickets and threads of this kind too often lately: - -> Add [this feature]. My company needs this and if you don't add this we won't use Gitlab. - -Also this: - -> We are expecting [this feature] in the next release. - -Or: - -> We must have [this feature]. Gitlab is useless without it and we'll go back to using Github. - -Why do people think they can make _demands_ like these? - -Is it too hard to read the installation guide that comes with the project? - -Don't get me wrong, it's awesome people are willing to try and install Gitlab. It's even more awesome people post their ideas and feature requests to further improve Gitlab. - -However, the **lack of respect** for people who spend their **free time** developing an open source application for you **to use for free** is sickening. - -No, really. Sickening. - -There really is no reason to _threaten_ or _pressure_ the people who are dedicating the free time, parts of the lives, to an open source project to implement something for you. - -Of course, some of you will say, "Just ignore those ass holes. They're not worth your time." I agree, but after reading two or three of these responses I don't feel like spending my evening off coding some awesomeness. - -This is a request to anyone who's ever going to post a feature request, a bug report or even a post to the mailing list of an open source project: - - * be polite, - * don't make threaths or demands, and - * show some respect for the souls who dedicate their time to making something awesome. - +_Edit: this is not a Gitlab specific issue. I've seen it before and I'm seeing it again at the Gitlab project._ + +The past few months I've been contributing to the [Gitlab](https://github.com/gitlabhq/gitlabhq) project. This has been a great experience, mostly because Gitlab has become a very popular project with over 2.3k watchers right now. + +It gives me great satisfaction knowing that my code is being used by hundreds if not thousands of people right now. But there is also this little thing that has been bugging me lately. + +There is a small core team of developers devoting time to the development of Gitlab. They do this passionatly and they have been cranking out releases and new features every 22nd of month for the past six months. + +A lot of effort has gone into making Gitlab what it is today. + +But with the rise in popularity there has also been an increased number issues, bugs and feature requests. The mailing list is also more active than ever. Of course, all of this is a good thing for an open source project, you would think. + +Most users appreciate the effort that goes into developing an application as complex as Gitlab. They appreciate the fact it's available for _free_. The appreciate somebody made time to develop a tool they can put to use on a daily basis. + +This appreciation is great motivator for the developers. Knowing their code is being put to good use only drives them write more code, more features. + +Unfortunately, I read tickets and threads of this kind too often lately: + +> Add [this feature]. My company needs this and if you don't add this we won't use Gitlab. + +Also this: + +> We are expecting [this feature] in the next release. + +Or: + +> We must have [this feature]. Gitlab is useless without it and we'll go back to using Github. + +Why do people think they can make _demands_ like these? + +Is it too hard to read the installation guide that comes with the project? + +Don't get me wrong, it's awesome people are willing to try and install Gitlab. It's even more awesome people post their ideas and feature requests to further improve Gitlab. + +However, the **lack of respect** for people who spend their **free time** developing an open source application for you **to use for free** is sickening. + +No, really. Sickening. + +There really is no reason to _threaten_ or _pressure_ the people who are dedicating the free time, parts of the lives, to an open source project to implement something for you. + +Of course, some of you will say, "Just ignore those ass holes. They're not worth your time." I agree, but after reading two or three of these responses I don't feel like spending my evening off coding some awesomeness. + +This is a request to anyone who's ever going to post a feature request, a bug report or even a post to the mailing list of an open source project: + + * be polite, + * don't make threaths or demands, and + * show some respect for the souls who dedicate their time to making something awesome. + **Open Source is a privilege. Not a right.** diff --git a/content/posts/2012-03-21-from-11-34s-to-0-625s-for-opening-a-rb-file-in-vim.md b/content/posts/2012/2012-03-21-from-11-34s-to-0-625s-for-opening-a-rb-file-in-vim.md similarity index 98% rename from content/posts/2012-03-21-from-11-34s-to-0-625s-for-opening-a-rb-file-in-vim.md rename to content/posts/2012/2012-03-21-from-11-34s-to-0-625s-for-opening-a-rb-file-in-vim.md index 7174a73..c054dd7 100644 --- a/content/posts/2012-03-21-from-11-34s-to-0-625s-for-opening-a-rb-file-in-vim.md +++ b/content/posts/2012/2012-03-21-from-11-34s-to-0-625s-for-opening-a-rb-file-in-vim.md @@ -4,48 +4,48 @@ title = "From 11.34s to 0.625s for opening a .rb file in Vim" tags = ["Ruby", "vim"] slug = "from-11-34s-to-0-625s-for-opening-a-rb-file-in-vim" +++ -Would you believe me if I told you that opening a simple Ruby file on my 2011 MacBook Pro takes 11.34 seconds? - -To test this, I've used this command: - - $ vim --startuptime log-before.txt app/models/user.rb - -This command will time everything that Vim does until the file is ready for you to edit down to the millisecond. This is a great way to find out what's slowing things down. - -I'll highlight the most interesting parts of [`log-before.txt`](https://gist.github.com/2147190#file_log_before.txt) here: - - 000.028 000.028: --- VIM STARTING --- - 6643.597 5496.976 5496.976: sourcing /usr/share/vim/vim73/ftplugin/ruby.vim - 11262.686 3963.993 3963.993: sourcing /Users/ariejan/.vim/bundle/vim-css-color/after/syntax/css.vim - 11263.907 3976.912 004.334: sourcing /usr/share/vim/vim73/syntax/html.vim - 11263.997 3977.361 000.449: sourcing /usr/share/vim/vim73/syntax/xhtml.vim - 11340.533 000.004: --- VIM STARTED --- - -These are the _big spenders_ of loading a ruby file. Firstly there is `ruby.vim` taking about 5.4 seconds to load. Then there is `css.vim` taking another 3.9 seconds - and this file doesn't even include CSS! - -These two time sinking hogs are keeping me back – 11 seconds at a time. - -Let's see, `vim-css-color`. This plugin shows color hashes in their actual colour. So `#00f` will have a blue background. Great when editing CSS files, but not all that import. I removed `vim-css-color`. - -_Note: the reason `vim-css-color` is slow with terminal vim is that is has to pre-compile colour hashes to ther xterm escape code equivalents. This is pretty time consuming._ - -Next up: `ruby.vim`. Why is this so bloody slow? - -As it turns out, Vim has trouble finding the right `ruby` for me. This can be remedied by adding the following snippet to your `~/.vimrc`. It sets a logical search path for `ruby`: - - if !empty($MY_RUBY_HOME) - let g:ruby_path = join(split(glob($MY_RUBY_HOME.'/lib/ruby/*.*')."\n".glob($MY_RUBY_HOME.'/lib/ruby/site_ruby/*'),"\n"),',') - endif - -Again I ran my timer command ([full output](https://gist.github.com/2147190#file_log_after.txt)): - - $ vim --startuptime log-after app/models/user.rb - -Now look at that: - - 000.034 000.034: --- VIM STARTING --- - 107.182 000.834 000.834: sourcing /usr/share/vim/vim73/ftplugin/ruby.vim - 625.001 000.003: --- VIM STARTED --- - +Would you believe me if I told you that opening a simple Ruby file on my 2011 MacBook Pro takes 11.34 seconds? + +To test this, I've used this command: + + $ vim --startuptime log-before.txt app/models/user.rb + +This command will time everything that Vim does until the file is ready for you to edit down to the millisecond. This is a great way to find out what's slowing things down. + +I'll highlight the most interesting parts of [`log-before.txt`](https://gist.github.com/2147190#file_log_before.txt) here: + + 000.028 000.028: --- VIM STARTING --- + 6643.597 5496.976 5496.976: sourcing /usr/share/vim/vim73/ftplugin/ruby.vim + 11262.686 3963.993 3963.993: sourcing /Users/ariejan/.vim/bundle/vim-css-color/after/syntax/css.vim + 11263.907 3976.912 004.334: sourcing /usr/share/vim/vim73/syntax/html.vim + 11263.997 3977.361 000.449: sourcing /usr/share/vim/vim73/syntax/xhtml.vim + 11340.533 000.004: --- VIM STARTED --- + +These are the _big spenders_ of loading a ruby file. Firstly there is `ruby.vim` taking about 5.4 seconds to load. Then there is `css.vim` taking another 3.9 seconds - and this file doesn't even include CSS! + +These two time sinking hogs are keeping me back – 11 seconds at a time. + +Let's see, `vim-css-color`. This plugin shows color hashes in their actual colour. So `#00f` will have a blue background. Great when editing CSS files, but not all that import. I removed `vim-css-color`. + +_Note: the reason `vim-css-color` is slow with terminal vim is that is has to pre-compile colour hashes to ther xterm escape code equivalents. This is pretty time consuming._ + +Next up: `ruby.vim`. Why is this so bloody slow? + +As it turns out, Vim has trouble finding the right `ruby` for me. This can be remedied by adding the following snippet to your `~/.vimrc`. It sets a logical search path for `ruby`: + + if !empty($MY_RUBY_HOME) + let g:ruby_path = join(split(glob($MY_RUBY_HOME.'/lib/ruby/*.*')."\n".glob($MY_RUBY_HOME.'/lib/ruby/site_ruby/*'),"\n"),',') + endif + +Again I ran my timer command ([full output](https://gist.github.com/2147190#file_log_after.txt)): + + $ vim --startuptime log-after app/models/user.rb + +Now look at that: + + 000.034 000.034: --- VIM STARTING --- + 107.182 000.834 000.834: sourcing /usr/share/vim/vim73/ftplugin/ruby.vim + 625.001 000.003: --- VIM STARTED --- + Yes, that is 0.625 seconds! I'm a happy ruby coder again. diff --git a/content/posts/2012-03-21-redis-using-2gb-of-memory-on-70mb-data-set-the-fix.md b/content/posts/2012/2012-03-21-redis-using-2gb-of-memory-on-70mb-data-set-the-fix.md similarity index 98% rename from content/posts/2012-03-21-redis-using-2gb-of-memory-on-70mb-data-set-the-fix.md rename to content/posts/2012/2012-03-21-redis-using-2gb-of-memory-on-70mb-data-set-the-fix.md index 471d4da..cbddc35 100644 --- a/content/posts/2012-03-21-redis-using-2gb-of-memory-on-70mb-data-set-the-fix.md +++ b/content/posts/2012/2012-03-21-redis-using-2gb-of-memory-on-70mb-data-set-the-fix.md @@ -4,45 +4,45 @@ title = "Redis using 2GB of memory on 70MB data set - the fix" tags = ["redis", "memory", "malloc", "jemalloc"] slug = "redis-using-2gb-of-memory-on-70mb-data-set-the-fix" +++ -For [Ariejan.net](http://ariejan.net) I use [redis](http://redis.io) to cache pages and shards. This works great and all, but today I noticed something alarming: - - redis Running 3d 12h 4m 0.0% 45.2% [1829556 kB] - -Yes, that's about 1.7 GB of RAM. That's way too much for what I cache. Let's see what redis has to say for itself: - - $ redis-cli - redis 127.0.0.1:6379> info - redis_version:2.2.12 - ... - connected_clients:5 - connected_slaves:0 - used_memory:71626608 - used_memory_human:68.31M - used_memory_rss:1873465344 - mem_fragmentation_ratio:26.16 - -Well, that's awkward. The OS is reporting 1.7GB memory usage, while Redis claims to store a mere 68MB. What's happening here! - -You may have noticed that I included `mem_fragmentation_ratio` in the snippet above as well. It's at a whopping 26.16, meaning that for every byte I store, 26.16 bytes of memory are used. This explains the 1.7GB memory usage. - -But, how do I get rid of this? My system has enough RAM to cope redis as is, but it's not a comforting thought to leave Redis running like this. - -As it turns out, there isn't a lot you can do about this. Redis 2.2 uses _malloc_ which causes the fragmentation. One alternative is to add a slave redis-server, migrate your data and then switch the slave to master. Although this is reported to work well, it's not a good solution to the problem. - -Fortunately, Redis 2.4 on Linux by default does not use _malloc_ anymore. Instead it uses _jemalloc_. From the redis README: - -> Redis is compiled and linked against libc malloc by default, with the exception of jemalloc being the default on Linux systems. This default was picked because jemalloc has proven to have fewer fragmentation problems than libc malloc. - -The only logical step to take is to upgrade to Redis 2.4. - -If you're already running (or just upgraded to) 2.4 you can easily check if your redis is using _jemalloc_: - - $ redis-cli - redis 127.0.0.1:6379> info - redis_version:2.4.9 - mem_fragmentation_ratio:1.11 - mem_allocator:jemalloc-2.2.5 - -I've taken this step and the `mem_fragmentation_ratio` samples I've measured have all been in the 1.1-1.4 regions. +For [Ariejan.net](http://ariejan.net) I use [redis](http://redis.io) to cache pages and shards. This works great and all, but today I noticed something alarming: + + redis Running 3d 12h 4m 0.0% 45.2% [1829556 kB] + +Yes, that's about 1.7 GB of RAM. That's way too much for what I cache. Let's see what redis has to say for itself: + + $ redis-cli + redis 127.0.0.1:6379> info + redis_version:2.2.12 + ... + connected_clients:5 + connected_slaves:0 + used_memory:71626608 + used_memory_human:68.31M + used_memory_rss:1873465344 + mem_fragmentation_ratio:26.16 + +Well, that's awkward. The OS is reporting 1.7GB memory usage, while Redis claims to store a mere 68MB. What's happening here! + +You may have noticed that I included `mem_fragmentation_ratio` in the snippet above as well. It's at a whopping 26.16, meaning that for every byte I store, 26.16 bytes of memory are used. This explains the 1.7GB memory usage. + +But, how do I get rid of this? My system has enough RAM to cope redis as is, but it's not a comforting thought to leave Redis running like this. + +As it turns out, there isn't a lot you can do about this. Redis 2.2 uses _malloc_ which causes the fragmentation. One alternative is to add a slave redis-server, migrate your data and then switch the slave to master. Although this is reported to work well, it's not a good solution to the problem. + +Fortunately, Redis 2.4 on Linux by default does not use _malloc_ anymore. Instead it uses _jemalloc_. From the redis README: + +> Redis is compiled and linked against libc malloc by default, with the exception of jemalloc being the default on Linux systems. This default was picked because jemalloc has proven to have fewer fragmentation problems than libc malloc. + +The only logical step to take is to upgrade to Redis 2.4. + +If you're already running (or just upgraded to) 2.4 you can easily check if your redis is using _jemalloc_: + + $ redis-cli + redis 127.0.0.1:6379> info + redis_version:2.4.9 + mem_fragmentation_ratio:1.11 + mem_allocator:jemalloc-2.2.5 + +I've taken this step and the `mem_fragmentation_ratio` samples I've measured have all been in the 1.1-1.4 regions. diff --git a/content/posts/2012-04-02-showing-ruby-rails-and-git-info-in-your-app.md b/content/posts/2012/2012-04-02-showing-ruby-rails-and-git-info-in-your-app.md similarity index 96% rename from content/posts/2012-04-02-showing-ruby-rails-and-git-info-in-your-app.md rename to content/posts/2012/2012-04-02-showing-ruby-rails-and-git-info-in-your-app.md index de4329a..252be76 100644 --- a/content/posts/2012-04-02-showing-ruby-rails-and-git-info-in-your-app.md +++ b/content/posts/2012/2012-04-02-showing-ruby-rails-and-git-info-in-your-app.md @@ -4,60 +4,60 @@ title = "Showing Ruby, Rails and git info in your app" tags = ["Ruby", "Rails", "protip"] slug = "showing-ruby-rails-and-git-info-in-your-app" +++ -Some people've asked me how I show rendering information on [ariejan.net](http://ariejan.net). - -![](https://ariejannet.s3.amazonaws.com/images/render_stats.jpg) - -There are a few things going on here, let me explain them one by one. - -### Rails version - -The current Rails version is probably the easiest you see here. Rails exposes its version information like this: - - Rails.version - -### Ruby version - -Ruby also exposes version information, albeit using constants: - - RUBY_VERSION - => "1.9.3" - -You may know that ruby also has different patch levels for each release. You can also retrieve that information: - - RUBY_PATCHLEVEL - => 125 - -The you may also want to know which engine you're using. This may be "ruby" or something different: - - RUBY_ENGINE - => "ruby" - -Combine these to get a sexy ruby version string: - - puts "#{RUBY_ENGINE}-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}" - => "ruby-1.9.3-p125" - -### Current process ID - -I like to know which Unicorn produced a certain page. Retrieving the process ID is easy: - - Process.pid - => 9473 - -### Current git revision SHA - -Knowing which version of your app is currently running can be useful information. To do this I created the following initializer: - - # config/initializers/git_revision.rb - module AppName - REVISION = `git log --pretty=format:'%h' -n 1` - end - -This will expose the current short SHA in your application's namespace: - - AppName::REVISION - => "ac6d3a0" - +Some people've asked me how I show rendering information on [ariejan.net](http://ariejan.net). + +![](https://ariejannet.s3.amazonaws.com/images/render_stats.jpg) + +There are a few things going on here, let me explain them one by one. + +### Rails version + +The current Rails version is probably the easiest you see here. Rails exposes its version information like this: + + Rails.version + +### Ruby version + +Ruby also exposes version information, albeit using constants: + + RUBY_VERSION + => "1.9.3" + +You may know that ruby also has different patch levels for each release. You can also retrieve that information: + + RUBY_PATCHLEVEL + => 125 + +The you may also want to know which engine you're using. This may be "ruby" or something different: + + RUBY_ENGINE + => "ruby" + +Combine these to get a sexy ruby version string: + + puts "#{RUBY_ENGINE}-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}" + => "ruby-1.9.3-p125" + +### Current process ID + +I like to know which Unicorn produced a certain page. Retrieving the process ID is easy: + + Process.pid + => 9473 + +### Current git revision SHA + +Knowing which version of your app is currently running can be useful information. To do this I created the following initializer: + + # config/initializers/git_revision.rb + module AppName + REVISION = `git log --pretty=format:'%h' -n 1` + end + +This will expose the current short SHA in your application's namespace: + + AppName::REVISION + => "ac6d3a0" + You can now use this info through-out your app to show version information. diff --git a/content/posts/2012-04-06-eindhoven-rb-lightning-talk-gitlab.md b/content/posts/2012/2012-04-06-eindhoven-rb-lightning-talk-gitlab.md similarity index 100% rename from content/posts/2012-04-06-eindhoven-rb-lightning-talk-gitlab.md rename to content/posts/2012/2012-04-06-eindhoven-rb-lightning-talk-gitlab.md diff --git a/content/posts/2012-04-14-decorating-devise-s-current_user-with-draper.md b/content/posts/2012/2012-04-14-decorating-devise-s-current_user-with-draper.md similarity index 97% rename from content/posts/2012-04-14-decorating-devise-s-current_user-with-draper.md rename to content/posts/2012/2012-04-14-decorating-devise-s-current_user-with-draper.md index baaca6d..956a5f2 100644 --- a/content/posts/2012-04-14-decorating-devise-s-current_user-with-draper.md +++ b/content/posts/2012/2012-04-14-decorating-devise-s-current_user-with-draper.md @@ -1,22 +1,22 @@ -+++ -date = "2012-04-14" -title = "Decorating Devise's current_user with Draper" -tags = ["Rails", "devise", "draper", "decorators"] -slug = "decorating-devise-s-current_user-with-draper" -+++ -I've become a big fan of decorators, especially [Draper](https://github.com/jcasimir/draper). - -Decorators allow you to move view related functionality for your models in to separate decorator classes. This keeps both your models and views clean and readable. - -Anyway, if you use Devise you're provided with a `current_user` helper. However, this helper returns an instance of `User` - without your decorators. To enable decorators for your `current_user` by default, simple add this to `app/controllers/application_controller.rb`: - -``` ruby -def current_user - UserDecorator.decorate(super) unless super.nil? -end -``` - -Now, anywhere in your views where you call `current_user` you'll get a decorated version instead. - -[Check here to see how to use Draper with Sorcery](http://ariejan.net/2012/11/02/decorating_sorcery_current_user_with_draper) - ++++ +date = "2012-04-14" +title = "Decorating Devise's current_user with Draper" +tags = ["Rails", "devise", "draper", "decorators"] +slug = "decorating-devise-s-current_user-with-draper" ++++ +I've become a big fan of decorators, especially [Draper](https://github.com/jcasimir/draper). + +Decorators allow you to move view related functionality for your models in to separate decorator classes. This keeps both your models and views clean and readable. + +Anyway, if you use Devise you're provided with a `current_user` helper. However, this helper returns an instance of `User` - without your decorators. To enable decorators for your `current_user` by default, simple add this to `app/controllers/application_controller.rb`: + +``` ruby +def current_user + UserDecorator.decorate(super) unless super.nil? +end +``` + +Now, anywhere in your views where you call `current_user` you'll get a decorated version instead. + +[Check here to see how to use Draper with Sorcery](http://ariejan.net/2012/11/02/decorating_sorcery_current_user_with_draper) + diff --git a/content/posts/2012-05-11-running-a-different-ruby-with-passenger-3-2-and-rvm.md b/content/posts/2012/2012-05-11-running-a-different-ruby-with-passenger-3-2-and-rvm.md similarity index 98% rename from content/posts/2012-05-11-running-a-different-ruby-with-passenger-3-2-and-rvm.md rename to content/posts/2012/2012-05-11-running-a-different-ruby-with-passenger-3-2-and-rvm.md index 5916775..6b51f92 100644 --- a/content/posts/2012-05-11-running-a-different-ruby-with-passenger-3-2-and-rvm.md +++ b/content/posts/2012/2012-05-11-running-a-different-ruby-with-passenger-3-2-and-rvm.md @@ -4,50 +4,50 @@ title = "Running a different ruby with Passenger 3.2 and RVM" tags = ["Ruby", "rvm", "passenger", "nginx"] slug = "running-a-different-ruby-with-passenger-3-2-and-rvm" +++ -Passenger 3.2 will have quite some nice new features. [1](http://blog.phusion.nl/2012/04/13/a-sneak-preview-of-phusion-passenger-3-2/) [2](http://blog.phusion.nl/2012/04/25/a-sneak-preview-of-phusion-passenger-3-2-part-2/) - -The features I'm looking forward to most is the ability to specify - per virtual server - which ruby to use. - -Before, you installed passenger and specified the required ruby version using `passenger_ruby`, like this in your `nginx.conf`: - - http { - passenger_root /opt/passenger; - passenger_ruby /usr/local/bin/ruby; - - server { - server_name ariejan.net; - passenger_enabled on; - } - } - -Now, if you added another server it would be forced to use the same ruby version. This might be okay for most servers, but for me not so much. I have several side-projects running on a single machine, and using only one ruby version is not optimal or even impossible. - -Now, with the upcoming Passenger 3.2 you can select a ruby version *per server*. This is awesome. All you have to do is move the `passenger_ruby`directive into the `server` block and all is set. Of course, you can leave the globally set ruby just as is. - - http { - passenger_root /opt/passenger; - passenger_ruby /usr/local/bin/ruby; - - server { - server_name ariejan.net; - passenger_enabled on; - passenger_ruby /home/deployer/.rvm/rubies/ruby-1.9.3-p194/bin/ruby; - } - } - -As you can see in the example above, I'm referencing ruby-1.9.3-p194, installed with RVM. - -### Installing "experimental" Passenger - -The installation is easy, as usual, but you must checkout the passenger source from Github and use the `experimental` branch. - -**Warning: do not install the `experimental` branch of Passenger on your production server unless you are absolutely sure what you're doing and you know how to rollback quickly and easily to a stable version of passenger.** - - cd /opt - git clone https://github.com/FooBarWidget/passenger.git - cd /opt/passenger - git checkout -b experimental origin/experimental - ./bin/passenger-install-nginx-module - +Passenger 3.2 will have quite some nice new features. [1](http://blog.phusion.nl/2012/04/13/a-sneak-preview-of-phusion-passenger-3-2/) [2](http://blog.phusion.nl/2012/04/25/a-sneak-preview-of-phusion-passenger-3-2-part-2/) + +The features I'm looking forward to most is the ability to specify - per virtual server - which ruby to use. + +Before, you installed passenger and specified the required ruby version using `passenger_ruby`, like this in your `nginx.conf`: + + http { + passenger_root /opt/passenger; + passenger_ruby /usr/local/bin/ruby; + + server { + server_name ariejan.net; + passenger_enabled on; + } + } + +Now, if you added another server it would be forced to use the same ruby version. This might be okay for most servers, but for me not so much. I have several side-projects running on a single machine, and using only one ruby version is not optimal or even impossible. + +Now, with the upcoming Passenger 3.2 you can select a ruby version *per server*. This is awesome. All you have to do is move the `passenger_ruby`directive into the `server` block and all is set. Of course, you can leave the globally set ruby just as is. + + http { + passenger_root /opt/passenger; + passenger_ruby /usr/local/bin/ruby; + + server { + server_name ariejan.net; + passenger_enabled on; + passenger_ruby /home/deployer/.rvm/rubies/ruby-1.9.3-p194/bin/ruby; + } + } + +As you can see in the example above, I'm referencing ruby-1.9.3-p194, installed with RVM. + +### Installing "experimental" Passenger + +The installation is easy, as usual, but you must checkout the passenger source from Github and use the `experimental` branch. + +**Warning: do not install the `experimental` branch of Passenger on your production server unless you are absolutely sure what you're doing and you know how to rollback quickly and easily to a stable version of passenger.** + + cd /opt + git clone https://github.com/FooBarWidget/passenger.git + cd /opt/passenger + git checkout -b experimental origin/experimental + ./bin/passenger-install-nginx-module + diff --git a/content/posts/2012-05-19-what-happened-to-downloading-games-from-the-pirate-bay.md b/content/posts/2012/2012-05-19-what-happened-to-downloading-games-from-the-pirate-bay.md similarity index 98% rename from content/posts/2012-05-19-what-happened-to-downloading-games-from-the-pirate-bay.md rename to content/posts/2012/2012-05-19-what-happened-to-downloading-games-from-the-pirate-bay.md index 23e3365..a4c8cbf 100644 --- a/content/posts/2012-05-19-what-happened-to-downloading-games-from-the-pirate-bay.md +++ b/content/posts/2012/2012-05-19-what-happened-to-downloading-games-from-the-pirate-bay.md @@ -4,25 +4,25 @@ title = "What happened to downloading games from The Pirate Bay?" tags = ["piracy", "diablo3", "steam"] slug = "what-happened-to-downloading-games-from-the-pirate-bay" +++ -This post is on piracy. Piracy of software, games, movies, music and other virtual goods. - -Before I continue writing this post let me confess to you that I used to use pirated software. I played games downloaded from the internet. And movies I watches 'on demand' by downloading them when I wanted to. There were times when there were no legally purchased songs on my iPod. - -After reinstalling my Mac a few weeks ago I noticed something remarkable. There is not a single piece of pirated software on my Mac. Everything has been paid for or is free / open-source. The same goes for my gaming rig, all games are legally purchased. - -This is in shrill contrast to a few years ago. What the fuck happened? - -Then I saw Diablo 3 was released. I'm not a huge fan of the franchise, but wanted to play Diablo 3 anyway. So, what to do. - -Checking with local and online retailers I can get a fair price of €49 euro - but the game is either sold out or will not be delivered in the next few days. I want to play Diablo 3 ** RIGHT THE FUCK NOW**. - -Okay, let's check with Blizzard then, the Battle.net store. They have the digital download version of Diablo 3, but for €59. It is instantly available, though. - -Clickety-Click, Diablo 3 purchased. Download ready in 16 minutes. Playing 5 minutes later. - -It's been said many times before, and it will be said many times again: _buying digital goods should be easy, fast and secure._ - -I've amazed myself by forking out an additional €10 to get easy access to Diablo 3. But I'm a happy customer and I bet Blizzard is also happy to have sold another Diablo 3 copy. - +This post is on piracy. Piracy of software, games, movies, music and other virtual goods. + +Before I continue writing this post let me confess to you that I used to use pirated software. I played games downloaded from the internet. And movies I watches 'on demand' by downloading them when I wanted to. There were times when there were no legally purchased songs on my iPod. + +After reinstalling my Mac a few weeks ago I noticed something remarkable. There is not a single piece of pirated software on my Mac. Everything has been paid for or is free / open-source. The same goes for my gaming rig, all games are legally purchased. + +This is in shrill contrast to a few years ago. What the fuck happened? + +Then I saw Diablo 3 was released. I'm not a huge fan of the franchise, but wanted to play Diablo 3 anyway. So, what to do. + +Checking with local and online retailers I can get a fair price of €49 euro - but the game is either sold out or will not be delivered in the next few days. I want to play Diablo 3 ** RIGHT THE FUCK NOW**. + +Okay, let's check with Blizzard then, the Battle.net store. They have the digital download version of Diablo 3, but for €59. It is instantly available, though. + +Clickety-Click, Diablo 3 purchased. Download ready in 16 minutes. Playing 5 minutes later. + +It's been said many times before, and it will be said many times again: _buying digital goods should be easy, fast and secure._ + +I've amazed myself by forking out an additional €10 to get easy access to Diablo 3. But I'm a happy customer and I bet Blizzard is also happy to have sold another Diablo 3 copy. + Hopefully the entertainment industry will get this message soon. Because movies are the only thing that are still available to me when I want them through The Pirate Bay. diff --git a/content/posts/2012-05-20-why-diablo-3-s-drm-is-the-best-kind-there-is.md b/content/posts/2012/2012-05-20-why-diablo-3-s-drm-is-the-best-kind-there-is.md similarity index 99% rename from content/posts/2012-05-20-why-diablo-3-s-drm-is-the-best-kind-there-is.md rename to content/posts/2012/2012-05-20-why-diablo-3-s-drm-is-the-best-kind-there-is.md index 6666130..84c291f 100644 --- a/content/posts/2012-05-20-why-diablo-3-s-drm-is-the-best-kind-there-is.md +++ b/content/posts/2012/2012-05-20-why-diablo-3-s-drm-is-the-best-kind-there-is.md @@ -4,23 +4,23 @@ title = "Why Diablo 3's DRM is the best kind there is" tags = ["error", "diablo3", "rage", "drm"] slug = "why-diablo-3-s-drm-is-the-best-kind-there-is" +++ -I just tried to play Diablo 3, but could not log on due to server maintenance. Blizzard requires you to be _always online_ to play even single player campaigns. I've seen a lot of people rage about this, but Blizzard actually has very good reasons to do this. And they even kept you, as a player, in mind! - -![Diable 3 Rage](https://s3-eu-west-1.amazonaws.com/ariejannet/images/diablo_3_rage.jpg) - -First of all, what Blizzard is doing is not really DRM. - -Digital Rights Management is making sure you have authorization (from the providing party) to do something off-line. The best example is music. After _authorizing_ your computer you can play your DRM protected music. - -What Blizzard requires is you logging on to one of their servers to play Diablo 3. This sounds like DRM, but you are actually using Blizzard's servers to play. And for good reason! - -Diablo 3 contains several features that allow you to interact with other players. For example, you can easily interact with your friends and you can even join their games. There's also the Auction House, where you can trade items. - -These features are nothing new to World of Warcraft players, and it's not surprising they require a central server to make sure everything is fair. - -An added benefit of this _always online_ model is that Blizzard can closely monitor how players behave in the game, allowing them to fine-tune game balance with every update the release. - -So, there are many _wins_ for the player here. The big win for Blizzard is that they can be selective about whom they allow to enter the server: only people with a valid license key. - +I just tried to play Diablo 3, but could not log on due to server maintenance. Blizzard requires you to be _always online_ to play even single player campaigns. I've seen a lot of people rage about this, but Blizzard actually has very good reasons to do this. And they even kept you, as a player, in mind! + +![Diable 3 Rage](https://s3-eu-west-1.amazonaws.com/ariejannet/images/diablo_3_rage.jpg) + +First of all, what Blizzard is doing is not really DRM. + +Digital Rights Management is making sure you have authorization (from the providing party) to do something off-line. The best example is music. After _authorizing_ your computer you can play your DRM protected music. + +What Blizzard requires is you logging on to one of their servers to play Diablo 3. This sounds like DRM, but you are actually using Blizzard's servers to play. And for good reason! + +Diablo 3 contains several features that allow you to interact with other players. For example, you can easily interact with your friends and you can even join their games. There's also the Auction House, where you can trade items. + +These features are nothing new to World of Warcraft players, and it's not surprising they require a central server to make sure everything is fair. + +An added benefit of this _always online_ model is that Blizzard can closely monitor how players behave in the game, allowing them to fine-tune game balance with every update the release. + +So, there are many _wins_ for the player here. The big win for Blizzard is that they can be selective about whom they allow to enter the server: only people with a valid license key. + I know it's frustrating that you can't play Diablo 3 on a rainy sunday afternoon when you want to. But with a modern, social game like Diablo 3, being online is an absolute must. diff --git a/content/posts/2012-05-21-what-s-causing-all-that-disk-i-o-on-my-mac.md b/content/posts/2012/2012-05-21-what-s-causing-all-that-disk-i-o-on-my-mac.md similarity index 99% rename from content/posts/2012-05-21-what-s-causing-all-that-disk-i-o-on-my-mac.md rename to content/posts/2012/2012-05-21-what-s-causing-all-that-disk-i-o-on-my-mac.md index b3126b4..0cf4682 100644 --- a/content/posts/2012-05-21-what-s-causing-all-that-disk-i-o-on-my-mac.md +++ b/content/posts/2012/2012-05-21-what-s-causing-all-that-disk-i-o-on-my-mac.md @@ -4,29 +4,29 @@ title = "What's causing all that disk I/O on my Mac?" tags = ["osx", "mac", "disk-io", "troubleshooting"] slug = "what-s-causing-all-that-disk-i-o-on-my-mac" +++ -After doing a full re-install of my MacBook Pro a few weeks back to combat system slowness, I'm again struck with a slow system. - -The problem is that there's a lot of disk I/O going on. CPU and memory are fine. I'm just not sure what's causing this trouble. - -Luckily, there's an easy solution to find out what's doing disk I/O on you mac. - -Open up a terminal and run - - $ sudo fs_usage - 09:08:45.749208 read F=12 B=0x400 0.000210 W Sparrow.3845544 - 09:08:45.749274 lseek F=12 O=0x0602e000 0.000002 Sparrow.3845544 - 09:08:45.749279 read F=12 B=0x400 0.000005 Sparrow.3845544 - 09:08:45.749341 lseek F=12 O=0x06038c00 0.000002 Sparrow.3845544 - 09:08:45.750358 RdData[async] D=0x025aaf38 B=0x1000 /dev/disk0s2 0.028830 W Sparrow.3845547 - 09:08:45.750379 pread F=16 B=0x30 O=0x00b32730 0.028895 W Sparrow.3845547 - 09:08:45.750390 pread F=16 B=0x30 O=0x0de9a810 0.000008 Sparrow.3845547 - 09:08:45.750396 pread F=16 B=0x30 O=0x1f5ec5c0 0.000006 W Sparrow.3845547 - 09:08:45.750399 pread F=16 B=0x30 O=0x236c84a0 0.000003 Sparrow.3845547 - 09:08:45.750405 pread F=16 B=0x4b O=0x236c84b6 0.000002 Sparrow.3845547 - 09:08:45.750701 pread F=16 B=0x30 O=0x00c95f00 0.000007 Sparrow.3845547 - 09:08:45.758502 RdData[async] D=0x04f0b608 B=0x1000 /dev/disk0s2 0.009148 W - -What you see here is Sparrow doing mad reads ot my disk. I'm not sure what it's doing, but it must stop. After killing Sparrow disk I/O goes down to normal, workable levels again. - +After doing a full re-install of my MacBook Pro a few weeks back to combat system slowness, I'm again struck with a slow system. + +The problem is that there's a lot of disk I/O going on. CPU and memory are fine. I'm just not sure what's causing this trouble. + +Luckily, there's an easy solution to find out what's doing disk I/O on you mac. + +Open up a terminal and run + + $ sudo fs_usage + 09:08:45.749208 read F=12 B=0x400 0.000210 W Sparrow.3845544 + 09:08:45.749274 lseek F=12 O=0x0602e000 0.000002 Sparrow.3845544 + 09:08:45.749279 read F=12 B=0x400 0.000005 Sparrow.3845544 + 09:08:45.749341 lseek F=12 O=0x06038c00 0.000002 Sparrow.3845544 + 09:08:45.750358 RdData[async] D=0x025aaf38 B=0x1000 /dev/disk0s2 0.028830 W Sparrow.3845547 + 09:08:45.750379 pread F=16 B=0x30 O=0x00b32730 0.028895 W Sparrow.3845547 + 09:08:45.750390 pread F=16 B=0x30 O=0x0de9a810 0.000008 Sparrow.3845547 + 09:08:45.750396 pread F=16 B=0x30 O=0x1f5ec5c0 0.000006 W Sparrow.3845547 + 09:08:45.750399 pread F=16 B=0x30 O=0x236c84a0 0.000003 Sparrow.3845547 + 09:08:45.750405 pread F=16 B=0x4b O=0x236c84b6 0.000002 Sparrow.3845547 + 09:08:45.750701 pread F=16 B=0x30 O=0x00c95f00 0.000007 Sparrow.3845547 + 09:08:45.758502 RdData[async] D=0x04f0b608 B=0x1000 /dev/disk0s2 0.009148 W + +What you see here is Sparrow doing mad reads ot my disk. I'm not sure what it's doing, but it must stop. After killing Sparrow disk I/O goes down to normal, workable levels again. + Now, to pick another mail client for Mac... diff --git a/content/posts/2012-05-22-ruby-regex-scanning-in-a-case-statement.md b/content/posts/2012/2012-05-22-ruby-regex-scanning-in-a-case-statement.md similarity index 96% rename from content/posts/2012-05-22-ruby-regex-scanning-in-a-case-statement.md rename to content/posts/2012/2012-05-22-ruby-regex-scanning-in-a-case-statement.md index ff219d9..3833c41 100644 --- a/content/posts/2012-05-22-ruby-regex-scanning-in-a-case-statement.md +++ b/content/posts/2012/2012-05-22-ruby-regex-scanning-in-a-case-statement.md @@ -1,19 +1,19 @@ -+++ -date = "2012-05-22" -title = "Ruby: regex scanning in a case statement" -tags = ["Ruby", "snippet"] -slug = "ruby-regex-scanning-in-a-case-statement" -+++ -Here's a handy ruby snippet that might come in handy one day. - -When the regex matches (input should end with " today"), you can directly grab the matched value using the special `$1` variable. - -``` ruby -case input -when /(.*)\stoday$/i then - puts "Today: #{$1}" -end -``` - -I think you can see how you can bend this to your own needs. - ++++ +date = "2012-05-22" +title = "Ruby: regex scanning in a case statement" +tags = ["Ruby", "snippet"] +slug = "ruby-regex-scanning-in-a-case-statement" ++++ +Here's a handy ruby snippet that might come in handy one day. + +When the regex matches (input should end with " today"), you can directly grab the matched value using the special `$1` variable. + +``` ruby +case input +when /(.*)\stoday$/i then + puts "Today: #{$1}" +end +``` + +I think you can see how you can bend this to your own needs. + diff --git a/content/posts/2012-05-23-how-star-trek-has-shaped-our-technology-and-future.md b/content/posts/2012/2012-05-23-how-star-trek-has-shaped-our-technology-and-future.md similarity index 98% rename from content/posts/2012-05-23-how-star-trek-has-shaped-our-technology-and-future.md rename to content/posts/2012/2012-05-23-how-star-trek-has-shaped-our-technology-and-future.md index 209f57f..869393d 100644 --- a/content/posts/2012-05-23-how-star-trek-has-shaped-our-technology-and-future.md +++ b/content/posts/2012/2012-05-23-how-star-trek-has-shaped-our-technology-and-future.md @@ -4,45 +4,45 @@ title = "How Star Trek has shaped our technology and future" tags = ["star trek", "sci-fi", "wtfomg"] slug = "how-star-trek-has-shaped-our-technology-and-future" +++ -You have probably watched Star Trek. Even if you don't like it, I bet you've seen at least a few episodes of _The Next Generation_ or a movie. - -Regardless of you opinion on Star Trek, its cool to see that current technology was only Science-Fiction ten or twenty years ago. - -Let's start with a simple example - the Communicator. Press a button and talk to anyone wirelessly, wherever they are. Reminds you of that mobile phone you carry around all day, doesn't it? - -Well, if that doesn't convince you, then check out the [Vocera B3000 Communication Bagde](http://www.vocera.com/) - -But there's more. Are you afraid of needles? Wouldn't it be totally cool if they didn't have to stick metal tubes into your arm to give you meds? Well, the can! Enter [SonoPrep](http://www.sontra.com/technology/) (Sorry, their site appears to be down). It'll weaking your sking in 15 seconds and you're ready to receive meds. You won't feel a thing. - -Warp Speeds? Try [Hyperdrive](http://en.wikipedia.org/wiki/Hyperdrive). - -Cloaking devices? [Got it](http://www.networkworld.com/community/node/13348?nwwpkg=slideshows) - -Phasers? [Check](http://latimesblogs.latimes.com/technology/2011/04/navy-laser-weapon-fire-.html) - -Medical Tricorder? [Sure, we can](http://www.networkworld.com/community/node/18946?nwwpkg=slideshows) - -Transparent Aluminium? [Yes, please](http://en.wikipedia.org/wiki/Aluminium_oxynitride) - -Okay, tractor beams then? [Oh, yeah](http://www.stanford.edu/group/blocklab/Optical%20Tweezers%20Introduction.htm) - -A huge library where you can just play about any tune in history? [Sweet mother of god, yes](http://www.spotify.com) - -Hand-Held devices that tell you your current location? [We have those too](https://buy.garmin.com/shop/shop.do?pID=63349&ra=true) - -PADD's? [Oh, yes!](http://www.apple.com/ipad/) - -Warp Core's and photon torpedo's? We'd need [Antimatter](http://en.wikipedia.org/wiki/Antimatter) for that, so we're getting there. - -I must admit that I was quite surprised to find some of these things already exist in current technology! I wonder how long it will take before we build our first _"USS Enterprise"_. - -Well, about 20 years. - -[Build the Enterprise](http://www.buildtheenterprise.org/) has thought about building a huge, Enterprise like, star ship. It's entirely feasable to built on in the next 20 years with proper funding (about half of what NASA got during its Apollo missions). - -Theoretically the Enterprise could be ready in 20 years. It could then take you to Mars in 90 days. The moon would take you 'only' 3. - -The future is now. - +You have probably watched Star Trek. Even if you don't like it, I bet you've seen at least a few episodes of _The Next Generation_ or a movie. + +Regardless of you opinion on Star Trek, its cool to see that current technology was only Science-Fiction ten or twenty years ago. + +Let's start with a simple example - the Communicator. Press a button and talk to anyone wirelessly, wherever they are. Reminds you of that mobile phone you carry around all day, doesn't it? + +Well, if that doesn't convince you, then check out the [Vocera B3000 Communication Bagde](http://www.vocera.com/) + +But there's more. Are you afraid of needles? Wouldn't it be totally cool if they didn't have to stick metal tubes into your arm to give you meds? Well, the can! Enter [SonoPrep](http://www.sontra.com/technology/) (Sorry, their site appears to be down). It'll weaking your sking in 15 seconds and you're ready to receive meds. You won't feel a thing. + +Warp Speeds? Try [Hyperdrive](http://en.wikipedia.org/wiki/Hyperdrive). + +Cloaking devices? [Got it](http://www.networkworld.com/community/node/13348?nwwpkg=slideshows) + +Phasers? [Check](http://latimesblogs.latimes.com/technology/2011/04/navy-laser-weapon-fire-.html) + +Medical Tricorder? [Sure, we can](http://www.networkworld.com/community/node/18946?nwwpkg=slideshows) + +Transparent Aluminium? [Yes, please](http://en.wikipedia.org/wiki/Aluminium_oxynitride) + +Okay, tractor beams then? [Oh, yeah](http://www.stanford.edu/group/blocklab/Optical%20Tweezers%20Introduction.htm) + +A huge library where you can just play about any tune in history? [Sweet mother of god, yes](http://www.spotify.com) + +Hand-Held devices that tell you your current location? [We have those too](https://buy.garmin.com/shop/shop.do?pID=63349&ra=true) + +PADD's? [Oh, yes!](http://www.apple.com/ipad/) + +Warp Core's and photon torpedo's? We'd need [Antimatter](http://en.wikipedia.org/wiki/Antimatter) for that, so we're getting there. + +I must admit that I was quite surprised to find some of these things already exist in current technology! I wonder how long it will take before we build our first _"USS Enterprise"_. + +Well, about 20 years. + +[Build the Enterprise](http://www.buildtheenterprise.org/) has thought about building a huge, Enterprise like, star ship. It's entirely feasable to built on in the next 20 years with proper funding (about half of what NASA got during its Apollo missions). + +Theoretically the Enterprise could be ready in 20 years. It could then take you to Mars in 90 days. The moon would take you 'only' 3. + +The future is now. + Note: Probably no one can tell if a specific technology or device was inspired by Star Trek or not. But it's very fascinating to see that stuff that was once thought-up by [Gene Roddenberry](http://en.wikipedia.org/wiki/Gene_Roddenberry) (and others) are already a reality. diff --git a/content/posts/2012-05-24-seo-is-bullshit.md b/content/posts/2012/2012-05-24-seo-is-bullshit.md similarity index 97% rename from content/posts/2012-05-24-seo-is-bullshit.md rename to content/posts/2012/2012-05-24-seo-is-bullshit.md index c04bbcb..7d5f1f5 100644 --- a/content/posts/2012-05-24-seo-is-bullshit.md +++ b/content/posts/2012/2012-05-24-seo-is-bullshit.md @@ -1,61 +1,61 @@ -+++ -date = "2012-05-24" -title = "SEO is bullshit" -tags = ["Opinion", "seo", "rant"] -slug = "seo-is-bullshit" -+++ - - - - -I get quite a lot of "oh we can SEO optimize your site for you" emails lately. I don't know why, but **SEO is bullshit**. Really. SEO is one of those _areas of expertise_ that are total rubbish. - -## Common SEO advice - -The most common advise regarding SEO includes: - - * Getting links to your site - * Add tons of keywords so the Google Crawler knows what you're talking about - * Add META data, lots of it - * Structure your page in some way for crawlers to understand better - * Add an XML sitemap - -There might be some merit in this, but you are optimizing your site for a _crawler_, a _computer program_ that interprets your site. Are crawlers your primary audience? If so, you have a sad site. - -_SEO Hacking_ is another common term I find in emails. SEO hacking tries to trick search engines to list your site higher for certain keywords. I won't go into the details, but basically you try to cheat a search engine's indexing rules. - -Some shady SEO companies even offer you a guarantee that you'll be the number 1 listen for certain keywords. Really? But how valuable is that? - -The problem with doing a lot of SEO hacks on your site is this: search engines and crawlers are continuiously updated to prevent hacking. Although this is not disclosed by Google, there are rumours that if you do actually use 'SEO hacks', you're site will be ranked lower, instead of higher. - -## The best SEO advice you can get - -So, what can you do to make people find your site? Simple: - -**Write. Good. Content.** - -Use headers like `

` and `` and `` tags to highlight import terms or words in your text — this is valuable to your readers as well. - -If your content is good, readers will find it. Link to it. Tweet about it. And crawlers will _always_ be able to index your site properly. Of course, it helps to tell people about your article using social media and other news sites for your niche. - -## So, not META-tags you say? - -No, that's not whaty I'm saying. META tags _do_ prodide information to crawlers, you should not assume they use that information in any way. For example, Ariejan.net has these META-tags: - -``` html - - -``` - -In Google, this results in a view like this: - -![Google Search Result for Ariejan.net](https://ariejannet.s3.amazonaws.com/images/ariejan-seo-example.jpg) - -Do note that the posts listed are considered popular by Google. Those are the post that are most visited and linked to on my site. - -## Conclusion - -If you get an email, promising you that for $200 you're site will be ranked nr. 1 for specific keywords: throw it away. - -The best SEO is writing awesome content people want to read. - ++++ +date = "2012-05-24" +title = "SEO is bullshit" +tags = ["Opinion", "seo", "rant"] +slug = "seo-is-bullshit" ++++ + + + + +I get quite a lot of "oh we can SEO optimize your site for you" emails lately. I don't know why, but **SEO is bullshit**. Really. SEO is one of those _areas of expertise_ that are total rubbish. + +## Common SEO advice + +The most common advise regarding SEO includes: + + * Getting links to your site + * Add tons of keywords so the Google Crawler knows what you're talking about + * Add META data, lots of it + * Structure your page in some way for crawlers to understand better + * Add an XML sitemap + +There might be some merit in this, but you are optimizing your site for a _crawler_, a _computer program_ that interprets your site. Are crawlers your primary audience? If so, you have a sad site. + +_SEO Hacking_ is another common term I find in emails. SEO hacking tries to trick search engines to list your site higher for certain keywords. I won't go into the details, but basically you try to cheat a search engine's indexing rules. + +Some shady SEO companies even offer you a guarantee that you'll be the number 1 listen for certain keywords. Really? But how valuable is that? + +The problem with doing a lot of SEO hacks on your site is this: search engines and crawlers are continuiously updated to prevent hacking. Although this is not disclosed by Google, there are rumours that if you do actually use 'SEO hacks', you're site will be ranked lower, instead of higher. + +## The best SEO advice you can get + +So, what can you do to make people find your site? Simple: + +**Write. Good. Content.** + +Use headers like `

` and `` and `` tags to highlight import terms or words in your text — this is valuable to your readers as well. + +If your content is good, readers will find it. Link to it. Tweet about it. And crawlers will _always_ be able to index your site properly. Of course, it helps to tell people about your article using social media and other news sites for your niche. + +## So, not META-tags you say? + +No, that's not whaty I'm saying. META tags _do_ prodide information to crawlers, you should not assume they use that information in any way. For example, Ariejan.net has these META-tags: + +``` html + + +``` + +In Google, this results in a view like this: + +![Google Search Result for Ariejan.net](https://ariejannet.s3.amazonaws.com/images/ariejan-seo-example.jpg) + +Do note that the posts listed are considered popular by Google. Those are the post that are most visited and linked to on my site. + +## Conclusion + +If you get an email, promising you that for $200 you're site will be ranked nr. 1 for specific keywords: throw it away. + +The best SEO is writing awesome content people want to read. + diff --git a/content/posts/2012-06-18-search-and-replace-in-multiple-files-with-vim.md b/content/posts/2012/2012-06-18-search-and-replace-in-multiple-files-with-vim.md similarity index 97% rename from content/posts/2012-06-18-search-and-replace-in-multiple-files-with-vim.md rename to content/posts/2012/2012-06-18-search-and-replace-in-multiple-files-with-vim.md index 6f27977..412ac26 100644 --- a/content/posts/2012-06-18-search-and-replace-in-multiple-files-with-vim.md +++ b/content/posts/2012/2012-06-18-search-and-replace-in-multiple-files-with-vim.md @@ -1,56 +1,56 @@ -+++ -date = "2012-06-18" -title = "Search and Replace in multiple files with Vim" -tags = ["Rails", "vim"] -slug = "search-and-replace-in-multiple-files-with-vim" -+++ - -I recently learned a nice VimTrick™ when pairing with [Arjan](http://arjanvandergaag.nl). We upgrade an app to Rails 3.2.6 and got the following deprecation message: - -``` text -DEPRECATION WARNING: :confirm option is deprecated and will be removed from Rails 4.0. -Use ':data => { :confirm => 'Text' }' instead. -``` - -Well, nothing difficult about that, but we have quite a few `:confirm` in this app. - -Firstly we checked where we used them (note we use ruby 1.9 hash syntax everywhere): - -``` shell -ack -l "confirm:" app -``` - -Now you have a listing of all the files that contain the `:confirm` hash key. You can leave out the `-l` option to get some context for each find. - -Now, we need to open Vim with those files: - -``` shell -ack -l "confirm:" app | xargs -o vim -``` - -Vim will open the first of these files. Here's a snippet of what you may find: - -``` haml -= link_to "Delete", something_path, confirm: "Are you sure?" -``` - -Now, search and replace is easy: - -``` vim -:%s/confirm: ".*"/data: { & }/g -``` - -This will surround the current confirm with the `data` hash. Just the way Rails likes it. The `&` character will be replaced with whatever text matched the search pattern. - -You could repeat this for every file manually. But, you're using Vim. - -``` vim -:argdo %s/confirm: ".*"/data: { & }/g | update -``` - -This will perform the search and replace on each of the supplied arguments (in this case the files selected with `ack`) and update (e.g. save) those files. - -Now you can quit Vim and enjoy the glory of all the disappearing deprecation warnings. - -Note: to do this with the ruby 1.8 hash syntax, just update the search and replace texts accordingly. - ++++ +date = "2012-06-18" +title = "Search and Replace in multiple files with Vim" +tags = ["Rails", "vim"] +slug = "search-and-replace-in-multiple-files-with-vim" ++++ + +I recently learned a nice VimTrick™ when pairing with [Arjan](http://arjanvandergaag.nl). We upgrade an app to Rails 3.2.6 and got the following deprecation message: + +``` text +DEPRECATION WARNING: :confirm option is deprecated and will be removed from Rails 4.0. +Use ':data => { :confirm => 'Text' }' instead. +``` + +Well, nothing difficult about that, but we have quite a few `:confirm` in this app. + +Firstly we checked where we used them (note we use ruby 1.9 hash syntax everywhere): + +``` shell +ack -l "confirm:" app +``` + +Now you have a listing of all the files that contain the `:confirm` hash key. You can leave out the `-l` option to get some context for each find. + +Now, we need to open Vim with those files: + +``` shell +ack -l "confirm:" app | xargs -o vim +``` + +Vim will open the first of these files. Here's a snippet of what you may find: + +``` haml += link_to "Delete", something_path, confirm: "Are you sure?" +``` + +Now, search and replace is easy: + +``` vim +:%s/confirm: ".*"/data: { & }/g +``` + +This will surround the current confirm with the `data` hash. Just the way Rails likes it. The `&` character will be replaced with whatever text matched the search pattern. + +You could repeat this for every file manually. But, you're using Vim. + +``` vim +:argdo %s/confirm: ".*"/data: { & }/g | update +``` + +This will perform the search and replace on each of the supplied arguments (in this case the files selected with `ack`) and update (e.g. save) those files. + +Now you can quit Vim and enjoy the glory of all the disappearing deprecation warnings. + +Note: to do this with the ruby 1.8 hash syntax, just update the search and replace texts accordingly. + diff --git a/content/posts/2012-07-11-vpn-too-complicated-use-a-ip-over-ssh-tunnel-instead.md b/content/posts/2012/2012-07-11-vpn-too-complicated-use-a-ip-over-ssh-tunnel-instead.md similarity index 97% rename from content/posts/2012-07-11-vpn-too-complicated-use-a-ip-over-ssh-tunnel-instead.md rename to content/posts/2012/2012-07-11-vpn-too-complicated-use-a-ip-over-ssh-tunnel-instead.md index 00a90c8..7c04938 100644 --- a/content/posts/2012-07-11-vpn-too-complicated-use-a-ip-over-ssh-tunnel-instead.md +++ b/content/posts/2012/2012-07-11-vpn-too-complicated-use-a-ip-over-ssh-tunnel-instead.md @@ -1,74 +1,74 @@ -+++ -date = "2012-07-11" -title = "VPN too complicated? Use a IP-over-SSH tunnel instead" -tags = ["ssh", "vpn", "hacks", "tunnel"] -slug = "vpn-too-complicated-use-a-ip-over-ssh-tunnel-instead" -+++ -Some times you find yourself in a place where your Mac is safely tucked away behind a firewall. That's great, but sometimes it is annoying as hell, because you _need_ to access resources over FTP or contact people who're on IRC. - -The normal solution would be to setup a VPN with one of your servers elsewhere and connect to the outside world that way. Unfortunately, in all their wisdom, sys admins have probably closed up the proper ports to access your VPN server as well. - -As a last resort you might consider setting up a SSH Tunnel for a specific service like this: - -``` shell -ssh -N user@server -L 3306:127.0.0.1:3306 -``` - -But, this only works for a single port, and thus application. It may help, but it can become tedious pretty quickly. You also have to rewrite any configuration you had for connection to a remote host to use your localhost, most likely on some strange port. - -Luckily for us, there's this awesome tool called [sshuttle]. - -Sshuttle allows you to setup what's called IP-over-SSH. Basically it runs a local proxy server to a remote server over SSH and changes the routing for your machine to send everything through that proxy. - -Besides giving you access to all the services you need, you also encrypt (e.g. hide) all your traffic from the prying eyes of any sys admins on the local network. - -Installing sshuttle on your Mac is a breeze - -``` shell -brew install sshuttle -``` - -Then you can setup an IP-over-SSH connection to any remote server you have SSH access to. You'll need your local admin password in order to setup routing properly. - -``` shell -sshuttle -r username@server 0/0 -vv -``` - -This routes all traffic over the tunnel towards `server`. Use on of those online ip checkers to see that you're actually using your `server`'s IP address. - -In the future you may want to change the `-vv` verbose option out and swap in `-D` to run in daemon mode. - -The one thing this does _not_ do is DNS. DNS is still done using your locally configured DNS server, mostly for speed. - -Not to worry, you can go 'full stealth' with the `--dns` options, which also routes DNS over to the remote server: - -``` shell -sshuttle --dns -r username@server 0/0 -vv -``` - -To stop using your IP-over-SSH connection, simply press CTRL-C twice and sshuttle should restore your normal networking connections. - -If sshuttle does not restore the connection properly, you can do so manually: - -``` shell -sudo ipfw -q -f flush -``` - -I've already create a few aliases in my `~/.zshrc`: - -``` shell -alias tunnel='sshuttle -r ariejan@server 0/0 -vv' -alias tunnel_dns='sshuttle --dns -r ariejan@server 0/0 -vv' -alias reset_tunnel='sudo ipfw -q -f flush' -``` - -So, no need to setup complicated VPN contraptions, just use plain old SSH and off you go. - -Bonus: you can also connect to a non-standard SSH port, in case port 22 has been blocked in the firewall as well: - -``` shell -sshuttle --dns -r username@server:port 0/0 -vv -``` - -[sshuttle]: https://github.com/apenwarr/sshuttle/ - ++++ +date = "2012-07-11" +title = "VPN too complicated? Use a IP-over-SSH tunnel instead" +tags = ["ssh", "vpn", "hacks", "tunnel"] +slug = "vpn-too-complicated-use-a-ip-over-ssh-tunnel-instead" ++++ +Some times you find yourself in a place where your Mac is safely tucked away behind a firewall. That's great, but sometimes it is annoying as hell, because you _need_ to access resources over FTP or contact people who're on IRC. + +The normal solution would be to setup a VPN with one of your servers elsewhere and connect to the outside world that way. Unfortunately, in all their wisdom, sys admins have probably closed up the proper ports to access your VPN server as well. + +As a last resort you might consider setting up a SSH Tunnel for a specific service like this: + +``` shell +ssh -N user@server -L 3306:127.0.0.1:3306 +``` + +But, this only works for a single port, and thus application. It may help, but it can become tedious pretty quickly. You also have to rewrite any configuration you had for connection to a remote host to use your localhost, most likely on some strange port. + +Luckily for us, there's this awesome tool called [sshuttle]. + +Sshuttle allows you to setup what's called IP-over-SSH. Basically it runs a local proxy server to a remote server over SSH and changes the routing for your machine to send everything through that proxy. + +Besides giving you access to all the services you need, you also encrypt (e.g. hide) all your traffic from the prying eyes of any sys admins on the local network. + +Installing sshuttle on your Mac is a breeze + +``` shell +brew install sshuttle +``` + +Then you can setup an IP-over-SSH connection to any remote server you have SSH access to. You'll need your local admin password in order to setup routing properly. + +``` shell +sshuttle -r username@server 0/0 -vv +``` + +This routes all traffic over the tunnel towards `server`. Use on of those online ip checkers to see that you're actually using your `server`'s IP address. + +In the future you may want to change the `-vv` verbose option out and swap in `-D` to run in daemon mode. + +The one thing this does _not_ do is DNS. DNS is still done using your locally configured DNS server, mostly for speed. + +Not to worry, you can go 'full stealth' with the `--dns` options, which also routes DNS over to the remote server: + +``` shell +sshuttle --dns -r username@server 0/0 -vv +``` + +To stop using your IP-over-SSH connection, simply press CTRL-C twice and sshuttle should restore your normal networking connections. + +If sshuttle does not restore the connection properly, you can do so manually: + +``` shell +sudo ipfw -q -f flush +``` + +I've already create a few aliases in my `~/.zshrc`: + +``` shell +alias tunnel='sshuttle -r ariejan@server 0/0 -vv' +alias tunnel_dns='sshuttle --dns -r ariejan@server 0/0 -vv' +alias reset_tunnel='sudo ipfw -q -f flush' +``` + +So, no need to setup complicated VPN contraptions, just use plain old SSH and off you go. + +Bonus: you can also connect to a non-standard SSH port, in case port 22 has been blocked in the firewall as well: + +``` shell +sshuttle --dns -r username@server:port 0/0 -vv +``` + +[sshuttle]: https://github.com/apenwarr/sshuttle/ + diff --git a/content/posts/2012-08-14-move-your-latest-commits-to-a-separate-branch.md b/content/posts/2012/2012-08-14-move-your-latest-commits-to-a-separate-branch.md similarity index 96% rename from content/posts/2012-08-14-move-your-latest-commits-to-a-separate-branch.md rename to content/posts/2012/2012-08-14-move-your-latest-commits-to-a-separate-branch.md index 219ad5a..15f49da 100644 --- a/content/posts/2012-08-14-move-your-latest-commits-to-a-separate-branch.md +++ b/content/posts/2012/2012-08-14-move-your-latest-commits-to-a-separate-branch.md @@ -1,35 +1,35 @@ -+++ -date = "2012-08-14" -title = "Move your latest commits to a separate branch" -tags = ["git", "protip"] -slug = "move-your-latest-commits-to-a-separate-branch" -+++ -The situation is pretty straightforward. You have been making commits for that new feature in your `master` branch. Naughty you! - -Let's assume you want to have this: - -``` text -A - B - (C) - D - E - F -``` - -`C` was the last commit you pulled from `origin` and D, E and F are commits you just made but should have been in their own branch. This is what you wanted: - -``` text -A - B - (C) - \ D - E F -``` - -Step 1: Assuming you're at `F` on `master`, create a new branch with those commits: - -``` shell -git branch my_feature_branch -``` - -Then, still on `master`, reset back to commit `C`. This is 3 commits back. - -``` shell -git reset --hard HEAD~3 -``` - -Okay, you're `master` is now back at `C`, which you lasted pulled, and the `my_feature_branch` includes D, E and F. Just checkout `my_feature_branch` and continue work as usual. I'm sure no one saw what you just did. - ++++ +date = "2012-08-14" +title = "Move your latest commits to a separate branch" +tags = ["git", "protip"] +slug = "move-your-latest-commits-to-a-separate-branch" ++++ +The situation is pretty straightforward. You have been making commits for that new feature in your `master` branch. Naughty you! + +Let's assume you want to have this: + +``` text +A - B - (C) - D - E - F +``` + +`C` was the last commit you pulled from `origin` and D, E and F are commits you just made but should have been in their own branch. This is what you wanted: + +``` text +A - B - (C) + \ D - E F +``` + +Step 1: Assuming you're at `F` on `master`, create a new branch with those commits: + +``` shell +git branch my_feature_branch +``` + +Then, still on `master`, reset back to commit `C`. This is 3 commits back. + +``` shell +git reset --hard HEAD~3 +``` + +Okay, you're `master` is now back at `C`, which you lasted pulled, and the `my_feature_branch` includes D, E and F. Just checkout `my_feature_branch` and continue work as usual. I'm sure no one saw what you just did. + diff --git a/content/posts/2012-08-27-getting-started-with-arduino.md b/content/posts/2012/2012-08-27-getting-started-with-arduino.md similarity index 98% rename from content/posts/2012-08-27-getting-started-with-arduino.md rename to content/posts/2012/2012-08-27-getting-started-with-arduino.md index a930629..e7eb27f 100644 --- a/content/posts/2012-08-27-getting-started-with-arduino.md +++ b/content/posts/2012/2012-08-27-getting-started-with-arduino.md @@ -1,95 +1,95 @@ -+++ -date = "2012-08-27" -title = "Getting started with Arduino" -tags = ["arduino"] -slug = "getting-started-with-arduino" -+++ -I'm a software engineer. I don't do hardware. - -Well, that used to be the case. I did build some PC's back in the day, but that's where my involvement with electronics hardware ended. That's all changed after I purchased an [Arduino][1]. - -## Arduino - -Arduino is an easy to use hardare _and_ software platform for designers, developers and tinkerers. What? - -Well, Arduino is more than just a small piece of electronics hardware. It does include hardware. This is the Arduino Uno, the latest incarnation and the board you'll most likely purchase if you want to break into the world of Arduino - -![The Arduino Uno](https://ariejannet.s3.amazonaws.com/images/arduino/impression.jpeg) - -This Arduino has some nice features you should know about. At its core it has the [Atmel Atmega328][2] chip. It has 32Kb of flashmemory and usually runs at 16MHz. Now this may not sound like much, but note that this is not like your average Intel Core i7 processor. This chip does several things for you, but the most important part is that you can program it to interact with the outside word through its 14 I/O pins. It gets its power over USB or from a battery that can supply 7-12V. - -As I said earlier, Arduino is more than just the hardware board. It also contains software. Software on the Atmega328 chip, called the bootloader, allows you to easily interact with the Arduino from your computer. Then there is the Arduino IDE, which you can install on Mac, Linux and Windows. This is the tool you write your code with and which allows you to upload that code to the Arduino. - -Now the great part is that both the hardware designs and the software are open-source. This means that you're free to buy all the separate components for an Arduino board and solder one yourself . You may even sell it if you like. The only catch is that you can't use the name _Arduino_. - -## An example - -The most basic thing you can do with Arduino is hook up a LED and resistor and make the LED blink. - -This is what that would look like if you'd build it: - -![Arduino Blink Setup](https://ariejannet.s3.amazonaws.com/images/arduino/ExampleCircuit_bb.png) - -This is the electrical schematic for this setup. It's very straight forward, as you can see, but enough to get you started. Even if you don't yet know how LED's work or what a resistor does, you can make this easily enough. - -_Note: if you do want to build this, I recommend you check out the [Blink tutorial][3] and buy an Arduino Starter Kit, which includes all the components to get started._ - -For those a bit tech-savvy, here's the electrical schematic for the Blink tutorial. I'm not going to explain it in to detail, but note that the led and resistor are connected to `D13` or pin 13 on the Arduino. - -![Arduino Blink Schematic](https://ariejannet.s3.amazonaws.com/images/arduino/ExampleCircuit_sch.png) - -With the following, relatively simple code, you can make that LED blink. - -``` arduino -int led = 13; // This refers to pin 13. - -// setup() is run once during start-up -void setup() { - // initialize the digital pin as an output. - pinMode(led, OUTPUT); -} - -// the loop routine runs over and over again forever: -void loop() { - digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) - delay(1000); // wait for a second - digitalWrite(led, LOW); // turn the LED off by making the voltage LOW - delay(1000); // wait for a second -} -``` - -After making this first step you'll get to know more components and features of Arduino. You'll start using sensors (buttons, light sensors, sound sensors, GPS, magnetometers, gas sensors) and you'll start using actuators (motors, steppers, relais, LED matrixes). The possibilities are endless. - -## The next step - -The great thing about Arduino is that it's designed to be easy to use. But is also offers great possibilities. - -For one, the Arduino Uno has only got 14 digital and 6 analog I/O pins. When you start using more other components you'll run out of I/O pins quickly. Enter the Arduino Mega which sports 54 digital and 16 analog I/O pins. Need something smaller: Arduino Nano, Need something to integrate into clothing: Arduino Lilypad. Need something custom: it's frickin' open-source, so design your own PCB, add the Arduino components you need and you're good to go. - -The things that are being doing with Arduino are amazing. The most important thing is that it makes electronics tinkering available to more people. It's pretty cheap to get started and learn about electronics. Then there are hundreds (if not more) possibilities to use Arduino, ranging for fancy LED matrix animations to the full-grown [Lawn Bot 400][4]: - -![Lawn Bot 400](https://ariejannet.s3.amazonaws.com/images/arduino/lawnbot.jpeg) - -## What's got all this to do with Ariejan.net? - -Of course, I'm a Rails web developer, but Arduino has sparked my interest. - -Over at Kabisa we've already done a small side-project using Arduino to scan and log RFID-tags - we'll be deploying this at a Rails conference later this year (and we'll be using it to give away some awesome prizes). - -In the scarce spare-time I have I'm planning on going beyond the blinking LED and build a 4WD Robot. I'll post my progress here at Ariejan.net. Keep an eye on the [Arduino section][5] for updates. - -It'll take me some months to get my robot driving and doing the stuff I want it to do. But my dream project is building a Quadcopter. - -## What about you? - -You are still reading this? And you didn't get started with Arduino yet? Come on, find [your local Arduino distributor][6] or head over [http://arduino.cc][1] and get one. Start doing the tutorials and be ready to be pulled into the world of tinkering and hobby electronics. It's fun! - -_Images have been taken from [arduino.cc][1] with not so much permission._ - -[1]: http://arduino.cc/ -[2]: http://www.atmel.com/devices/atmega328.aspx -[3]: http://arduino.cc/en/Tutorial/blink -[4]: http://www.instructables.com/id/Arduino-RC-Lawnmower/ -[5]: http://ariejan.net/posts/tagged/arduino -[6]: http://arduino.cc/en/Main/Buy - ++++ +date = "2012-08-27" +title = "Getting started with Arduino" +tags = ["arduino"] +slug = "getting-started-with-arduino" ++++ +I'm a software engineer. I don't do hardware. + +Well, that used to be the case. I did build some PC's back in the day, but that's where my involvement with electronics hardware ended. That's all changed after I purchased an [Arduino][1]. + +## Arduino + +Arduino is an easy to use hardare _and_ software platform for designers, developers and tinkerers. What? + +Well, Arduino is more than just a small piece of electronics hardware. It does include hardware. This is the Arduino Uno, the latest incarnation and the board you'll most likely purchase if you want to break into the world of Arduino + +![The Arduino Uno](https://ariejannet.s3.amazonaws.com/images/arduino/impression.jpeg) + +This Arduino has some nice features you should know about. At its core it has the [Atmel Atmega328][2] chip. It has 32Kb of flashmemory and usually runs at 16MHz. Now this may not sound like much, but note that this is not like your average Intel Core i7 processor. This chip does several things for you, but the most important part is that you can program it to interact with the outside word through its 14 I/O pins. It gets its power over USB or from a battery that can supply 7-12V. + +As I said earlier, Arduino is more than just the hardware board. It also contains software. Software on the Atmega328 chip, called the bootloader, allows you to easily interact with the Arduino from your computer. Then there is the Arduino IDE, which you can install on Mac, Linux and Windows. This is the tool you write your code with and which allows you to upload that code to the Arduino. + +Now the great part is that both the hardware designs and the software are open-source. This means that you're free to buy all the separate components for an Arduino board and solder one yourself . You may even sell it if you like. The only catch is that you can't use the name _Arduino_. + +## An example + +The most basic thing you can do with Arduino is hook up a LED and resistor and make the LED blink. + +This is what that would look like if you'd build it: + +![Arduino Blink Setup](https://ariejannet.s3.amazonaws.com/images/arduino/ExampleCircuit_bb.png) + +This is the electrical schematic for this setup. It's very straight forward, as you can see, but enough to get you started. Even if you don't yet know how LED's work or what a resistor does, you can make this easily enough. + +_Note: if you do want to build this, I recommend you check out the [Blink tutorial][3] and buy an Arduino Starter Kit, which includes all the components to get started._ + +For those a bit tech-savvy, here's the electrical schematic for the Blink tutorial. I'm not going to explain it in to detail, but note that the led and resistor are connected to `D13` or pin 13 on the Arduino. + +![Arduino Blink Schematic](https://ariejannet.s3.amazonaws.com/images/arduino/ExampleCircuit_sch.png) + +With the following, relatively simple code, you can make that LED blink. + +``` arduino +int led = 13; // This refers to pin 13. + +// setup() is run once during start-up +void setup() { + // initialize the digital pin as an output. + pinMode(led, OUTPUT); +} + +// the loop routine runs over and over again forever: +void loop() { + digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) + delay(1000); // wait for a second + digitalWrite(led, LOW); // turn the LED off by making the voltage LOW + delay(1000); // wait for a second +} +``` + +After making this first step you'll get to know more components and features of Arduino. You'll start using sensors (buttons, light sensors, sound sensors, GPS, magnetometers, gas sensors) and you'll start using actuators (motors, steppers, relais, LED matrixes). The possibilities are endless. + +## The next step + +The great thing about Arduino is that it's designed to be easy to use. But is also offers great possibilities. + +For one, the Arduino Uno has only got 14 digital and 6 analog I/O pins. When you start using more other components you'll run out of I/O pins quickly. Enter the Arduino Mega which sports 54 digital and 16 analog I/O pins. Need something smaller: Arduino Nano, Need something to integrate into clothing: Arduino Lilypad. Need something custom: it's frickin' open-source, so design your own PCB, add the Arduino components you need and you're good to go. + +The things that are being doing with Arduino are amazing. The most important thing is that it makes electronics tinkering available to more people. It's pretty cheap to get started and learn about electronics. Then there are hundreds (if not more) possibilities to use Arduino, ranging for fancy LED matrix animations to the full-grown [Lawn Bot 400][4]: + +![Lawn Bot 400](https://ariejannet.s3.amazonaws.com/images/arduino/lawnbot.jpeg) + +## What's got all this to do with Ariejan.net? + +Of course, I'm a Rails web developer, but Arduino has sparked my interest. + +Over at Kabisa we've already done a small side-project using Arduino to scan and log RFID-tags - we'll be deploying this at a Rails conference later this year (and we'll be using it to give away some awesome prizes). + +In the scarce spare-time I have I'm planning on going beyond the blinking LED and build a 4WD Robot. I'll post my progress here at Ariejan.net. Keep an eye on the [Arduino section][5] for updates. + +It'll take me some months to get my robot driving and doing the stuff I want it to do. But my dream project is building a Quadcopter. + +## What about you? + +You are still reading this? And you didn't get started with Arduino yet? Come on, find [your local Arduino distributor][6] or head over [http://arduino.cc][1] and get one. Start doing the tutorials and be ready to be pulled into the world of tinkering and hobby electronics. It's fun! + +_Images have been taken from [arduino.cc][1] with not so much permission._ + +[1]: http://arduino.cc/ +[2]: http://www.atmel.com/devices/atmega328.aspx +[3]: http://arduino.cc/en/Tutorial/blink +[4]: http://www.instructables.com/id/Arduino-RC-Lawnmower/ +[5]: http://ariejan.net/posts/tagged/arduino +[6]: http://arduino.cc/en/Main/Buy + diff --git a/content/posts/2012-08-28-rails-migrations-decimal-precision-and-scale.md b/content/posts/2012/2012-08-28-rails-migrations-decimal-precision-and-scale.md similarity index 98% rename from content/posts/2012-08-28-rails-migrations-decimal-precision-and-scale.md rename to content/posts/2012/2012-08-28-rails-migrations-decimal-precision-and-scale.md index 0189a41..a38394d 100644 --- a/content/posts/2012-08-28-rails-migrations-decimal-precision-and-scale.md +++ b/content/posts/2012/2012-08-28-rails-migrations-decimal-precision-and-scale.md @@ -1,22 +1,22 @@ -+++ -date = "2012-08-28" -title = "Rails migrations: decimal precision and scale" -tags = ["Rails", "migrations", "postgresql"] -slug = "rails-migrations-decimal-precision-and-scale" -+++ -I'm always confused when using `decimal` in a Rails migration. Normally I need to store a value that has 2 or 3 numbers behind the comma (or dot), or decimals. - -Let's say you have a `Product` model with a `discount_percentage` attribute. This attribute is currently an integer, only allowing non-decimal values. To allow 2 digit decimal values (e.g. `12.54`), you can mak the following migration: - -``` ruby -change_column :products, :discount_percentage, :decimal, precision: 5, scale: 2 -``` - -This will allow you to store values like `80.00`, `99.99` and `100.00`. There are five digits in the entire number and of those five, two decimals. - -It's not necessary so specify `precision` and `scale` as your database will then allow any decimal value it can store. - -Read more about the `decimal` data type in PostgreSQL here: [http://www.postgresql.org/docs/9.1/static/datatype-numeric.html][1] - -[1]: http://www.postgresql.org/docs/9.1/static/datatype-numeric.html - ++++ +date = "2012-08-28" +title = "Rails migrations: decimal precision and scale" +tags = ["Rails", "migrations", "postgresql"] +slug = "rails-migrations-decimal-precision-and-scale" ++++ +I'm always confused when using `decimal` in a Rails migration. Normally I need to store a value that has 2 or 3 numbers behind the comma (or dot), or decimals. + +Let's say you have a `Product` model with a `discount_percentage` attribute. This attribute is currently an integer, only allowing non-decimal values. To allow 2 digit decimal values (e.g. `12.54`), you can mak the following migration: + +``` ruby +change_column :products, :discount_percentage, :decimal, precision: 5, scale: 2 +``` + +This will allow you to store values like `80.00`, `99.99` and `100.00`. There are five digits in the entire number and of those five, two decimals. + +It's not necessary so specify `precision` and `scale` as your database will then allow any decimal value it can store. + +Read more about the `decimal` data type in PostgreSQL here: [http://www.postgresql.org/docs/9.1/static/datatype-numeric.html][1] + +[1]: http://www.postgresql.org/docs/9.1/static/datatype-numeric.html + diff --git a/content/posts/2012-09-04-git-interactive-revert.md b/content/posts/2012/2012-09-04-git-interactive-revert.md similarity index 96% rename from content/posts/2012-09-04-git-interactive-revert.md rename to content/posts/2012/2012-09-04-git-interactive-revert.md index 196c9cd..66c9a17 100644 --- a/content/posts/2012-09-04-git-interactive-revert.md +++ b/content/posts/2012/2012-09-04-git-interactive-revert.md @@ -1,62 +1,62 @@ -+++ -date = "2012-09-04" -title = "Git: Interactive Revert" -tags = ["git", "protip"] -slug = "git-interactive-revert" -+++ -I recently made a commit in a project that, mistakenly, included changes to `db/schema.rb`. My local schema was out of date and this could cause trouble for the others in my team. - -Luckily we use [a successful git branching model][1] so my changes were still up for review by the team. - -The change I made was part of larger commit. But all I wanted was to revert serveral chunks from `db/schema.rb` that would cause trouble. - -## Interactive add - -Now, there's `git add -i` which allows you to selectively stage chunks for the next commit. Unfortunately, the process for reversing interactively is a bit more complicated, but not much. - -## Interactive revert - -Well, let's say you want to revert changes you made in commit `f1e11c`. Go to your feature branch and revert your changes for that commit but do not commit them yet, hence the `-n` option: - -``` shell -git revert -n f1e11c -``` - -Your working copy now contains staged changes to revert the entire `f1e11c` commit. You don't want to revert everything, so unstage all those changes. - -``` shell -git reset -``` - -The key now is to interactively stage the changes you want to revert. You can do this like this: - -``` shell -git add -p -``` - -or - -``` shell -git add -i -``` - -Choose whichever suits you. - -In my case I staged only the chunks that related to the changes in `db/schema.rb` that I wanted to revert. - -With your reverting changes staged, commit them. - -``` shell -git commit -``` - -You're now left with reverting changes you didn't want to make. Just throw them away. - -``` shell -git reset --hard -``` - -And that's all. You have now selectively reverted a commit. - -[1]: http://nvie.com/posts/a-successful-git-branching-model/ - ++++ +date = "2012-09-04" +title = "Git: Interactive Revert" +tags = ["git", "protip"] +slug = "git-interactive-revert" ++++ +I recently made a commit in a project that, mistakenly, included changes to `db/schema.rb`. My local schema was out of date and this could cause trouble for the others in my team. + +Luckily we use [a successful git branching model][1] so my changes were still up for review by the team. + +The change I made was part of larger commit. But all I wanted was to revert serveral chunks from `db/schema.rb` that would cause trouble. + +## Interactive add + +Now, there's `git add -i` which allows you to selectively stage chunks for the next commit. Unfortunately, the process for reversing interactively is a bit more complicated, but not much. + +## Interactive revert + +Well, let's say you want to revert changes you made in commit `f1e11c`. Go to your feature branch and revert your changes for that commit but do not commit them yet, hence the `-n` option: + +``` shell +git revert -n f1e11c +``` + +Your working copy now contains staged changes to revert the entire `f1e11c` commit. You don't want to revert everything, so unstage all those changes. + +``` shell +git reset +``` + +The key now is to interactively stage the changes you want to revert. You can do this like this: + +``` shell +git add -p +``` + +or + +``` shell +git add -i +``` + +Choose whichever suits you. + +In my case I staged only the chunks that related to the changes in `db/schema.rb` that I wanted to revert. + +With your reverting changes staged, commit them. + +``` shell +git commit +``` + +You're now left with reverting changes you didn't want to make. Just throw them away. + +``` shell +git reset --hard +``` + +And that's all. You have now selectively reverted a commit. + +[1]: http://nvie.com/posts/a-successful-git-branching-model/ + diff --git a/content/posts/2012-10-01-migrate-git-repositories.md b/content/posts/2012/2012-10-01-migrate-git-repositories.md similarity index 96% rename from content/posts/2012-10-01-migrate-git-repositories.md rename to content/posts/2012/2012-10-01-migrate-git-repositories.md index fd2f8c0..7e18cde 100644 --- a/content/posts/2012-10-01-migrate-git-repositories.md +++ b/content/posts/2012/2012-10-01-migrate-git-repositories.md @@ -1,25 +1,25 @@ -+++ -date = "2012-10-01" -title = "Migrate git repositories" -tags = ["git"] -slug = "migrate-git-repositories" -+++ -Sometimes you have to move your git repository to another host. In this case I want to move a privately hosted git repository to a brand spanking new github repository. - -These are four easy steps to get that done: - -``` shell -git clone --bare git@yourserver.com:project.git -cd project.git -git push --mirror git@github.com:ariejan/project.git -cd .. && rm -rf project.git -``` - -That's it. Don't forget to update the `remote` of your working copy accordingly: - -``` shell -git remote set-url origin git@github.com:ariejan/project.git -``` - -Of course, this works with any git server or service, not just Github, although Github is awesome and you should use it. - ++++ +date = "2012-10-01" +title = "Migrate git repositories" +tags = ["git"] +slug = "migrate-git-repositories" ++++ +Sometimes you have to move your git repository to another host. In this case I want to move a privately hosted git repository to a brand spanking new github repository. + +These are four easy steps to get that done: + +``` shell +git clone --bare git@yourserver.com:project.git +cd project.git +git push --mirror git@github.com:ariejan/project.git +cd .. && rm -rf project.git +``` + +That's it. Don't forget to update the `remote` of your working copy accordingly: + +``` shell +git remote set-url origin git@github.com:ariejan/project.git +``` + +Of course, this works with any git server or service, not just Github, although Github is awesome and you should use it. + diff --git a/content/posts/2012-10-04-a-static-file-server-in-go.md b/content/posts/2012/2012-10-04-a-static-file-server-in-go.md similarity index 97% rename from content/posts/2012-10-04-a-static-file-server-in-go.md rename to content/posts/2012/2012-10-04-a-static-file-server-in-go.md index 25f0ab0..6fce0bc 100644 --- a/content/posts/2012-10-04-a-static-file-server-in-go.md +++ b/content/posts/2012/2012-10-04-a-static-file-server-in-go.md @@ -4,25 +4,25 @@ title = "A static file server in Go" tags = ["go"] slug = "a-static-file-server-in-go" +++ -If you don't know Go, you should really look into it. Today I was trying to figure out how to write a simple (and fast) static file server in Go. - -As it turns out, this is very easy to do. Go contains (in the `net/http` package) a nice `FileServer` type that can server files from the directory you point it to. - -Here's a sweet and short example: - - package main - - import ( - "net/http" - "log" - ) - - func main() { - err := http.ListenAndServe(":4242", http.FileServer(http.Dir("public"))) - if err != nil { - log.Printf("Error running web server for static assets: %v", err) - } - } - +If you don't know Go, you should really look into it. Today I was trying to figure out how to write a simple (and fast) static file server in Go. + +As it turns out, this is very easy to do. Go contains (in the `net/http` package) a nice `FileServer` type that can server files from the directory you point it to. + +Here's a sweet and short example: + + package main + + import ( + "net/http" + "log" + ) + + func main() { + err := http.ListenAndServe(":4242", http.FileServer(http.Dir("public"))) + if err != nil { + log.Printf("Error running web server for static assets: %v", err) + } + } + By itself this is not very useful, but you can easily integrate this into any other http server you create, maybe for handling dynamic requests or doing web sockets. diff --git a/content/posts/2012-11-02-decorating_sorcery_current_user_with_draper.md b/content/posts/2012/2012-11-02-decorating_sorcery_current_user_with_draper.md similarity index 100% rename from content/posts/2012-11-02-decorating_sorcery_current_user_with_draper.md rename to content/posts/2012/2012-11-02-decorating_sorcery_current_user_with_draper.md diff --git a/content/posts/2012-11-05-a-call-to-all-ci-service-providers.md b/content/posts/2012/2012-11-05-a-call-to-all-ci-service-providers.md similarity index 98% rename from content/posts/2012-11-05-a-call-to-all-ci-service-providers.md rename to content/posts/2012/2012-11-05-a-call-to-all-ci-service-providers.md index dd34464..3bb7c88 100644 --- a/content/posts/2012-11-05-a-call-to-all-ci-service-providers.md +++ b/content/posts/2012/2012-11-05-a-call-to-all-ci-service-providers.md @@ -4,64 +4,64 @@ title = "A Call to all CI Service Providers" tags = ["testing", "bdd", "tdd", "rant", "ci", "jenkins"] slug = "a-call-to-all-ci-service-providers" +++ -As a professional developer I test my code. Every check-in I do is tested either on [Kabisa][1]'s [Jenkins][2] server or on [Travis CI Pro][4]. - -For open source projects there's [Travis CI][3]. It's free and a great way to get to know Travis. - -Now, as an individual I have some side projects, most notably my own site, [Ariejan.net][7]. I value well written and well tested code as much for my own stuff as for my professional work. However, I don't have a Jenkins CI server in my basement. - -Looking around the internets there are a few CI services that can test my Ariejan.net Rails application, among them [Cirlce CI][5], [Atlassian Bamboo][8] and [Semaphore][6]. - -Now, the thing here is that to test the few projects I have (about four) it will cost me more to have the hosted in a CI services than actually running these apps. - - * Travis - $129/mo for 2 concurrent builds. - * Circle CI - $49/mo for 10 private projects. - * Semaphore - $39/mo for 5 private projects. - * Bamboo - $20/mo for 10 jobs.¹ - -_¹ Bamboo advertises $10/mo, but a $10/mo Jira subscription is also required._ - -As an individual, these prices are pretty steep for the few commits I make during the weekend. - -### Looking at Github and Heroku - -Let's take a look at github and heroku here. At heroku I pay nothing to host a site. Performance is limited, but it more often than not is sufficient for a side-project. Adding a worker or extra dyno costs about $38/mo. Still less than half of the CI services I mentioned. - -Having private repos with Github is also quite cheap. You'll get 5 for $7/mo. Which, converted, is about €1 per repo a month. - -Now, as an individual developer, I'm more than happy to use these services for these relatively low fees. - -### Where are the cheap, individual CI services? - -As an individual developer, this is what I need: - - * Unlimited, or at least 5-10 jobs/private projects. - * Low monthly cost: $5 - $10. - -What I don't need is: - - * Concurrency and paralellisation - * Immediate execution - * 24/7 Support - -I can do with a single worker doing one build at a time. I don't write enterprise CRM software in my weekends, you know. - -Also, I don't expect my build to execute immediately. I don't mind if there's a job queue and I have to wait a bit longer to get back results. - -### Business opportunity? - -IMHO there's a business opportunity here. Github and Heroku are great examples of how giving something away for free (or cheap) to individual developers creates a market for their product. - -I understand that CI takes a considerable amount of system resources and time, but having a good experience as an individual is more than likely to attrack people to your platform when they need a more profession plan. - -Who's stepping up to the plate? - -[1]: http://kabisa.nl -[2]: http://jenkins-ci.org -[3]: http://travis-ci.org -[4]: http://travis-ci.com -[5]: https://circleci.com -[6]: https://semaphoreapp.com -[7]: http://ariejan.net +As a professional developer I test my code. Every check-in I do is tested either on [Kabisa][1]'s [Jenkins][2] server or on [Travis CI Pro][4]. + +For open source projects there's [Travis CI][3]. It's free and a great way to get to know Travis. + +Now, as an individual I have some side projects, most notably my own site, [Ariejan.net][7]. I value well written and well tested code as much for my own stuff as for my professional work. However, I don't have a Jenkins CI server in my basement. + +Looking around the internets there are a few CI services that can test my Ariejan.net Rails application, among them [Cirlce CI][5], [Atlassian Bamboo][8] and [Semaphore][6]. + +Now, the thing here is that to test the few projects I have (about four) it will cost me more to have the hosted in a CI services than actually running these apps. + + * Travis - $129/mo for 2 concurrent builds. + * Circle CI - $49/mo for 10 private projects. + * Semaphore - $39/mo for 5 private projects. + * Bamboo - $20/mo for 10 jobs.¹ + +_¹ Bamboo advertises $10/mo, but a $10/mo Jira subscription is also required._ + +As an individual, these prices are pretty steep for the few commits I make during the weekend. + +### Looking at Github and Heroku + +Let's take a look at github and heroku here. At heroku I pay nothing to host a site. Performance is limited, but it more often than not is sufficient for a side-project. Adding a worker or extra dyno costs about $38/mo. Still less than half of the CI services I mentioned. + +Having private repos with Github is also quite cheap. You'll get 5 for $7/mo. Which, converted, is about €1 per repo a month. + +Now, as an individual developer, I'm more than happy to use these services for these relatively low fees. + +### Where are the cheap, individual CI services? + +As an individual developer, this is what I need: + + * Unlimited, or at least 5-10 jobs/private projects. + * Low monthly cost: $5 - $10. + +What I don't need is: + + * Concurrency and paralellisation + * Immediate execution + * 24/7 Support + +I can do with a single worker doing one build at a time. I don't write enterprise CRM software in my weekends, you know. + +Also, I don't expect my build to execute immediately. I don't mind if there's a job queue and I have to wait a bit longer to get back results. + +### Business opportunity? + +IMHO there's a business opportunity here. Github and Heroku are great examples of how giving something away for free (or cheap) to individual developers creates a market for their product. + +I understand that CI takes a considerable amount of system resources and time, but having a good experience as an individual is more than likely to attrack people to your platform when they need a more profession plan. + +Who's stepping up to the plate? + +[1]: http://kabisa.nl +[2]: http://jenkins-ci.org +[3]: http://travis-ci.org +[4]: http://travis-ci.com +[5]: https://circleci.com +[6]: https://semaphoreapp.com +[7]: http://ariejan.net [8]: http://www.atlassian.com/software/bamboo/ diff --git a/content/posts/2012-11-22-customac.md b/content/posts/2012/2012-11-22-customac.md similarity index 98% rename from content/posts/2012-11-22-customac.md rename to content/posts/2012/2012-11-22-customac.md index 7907351..1166aa6 100644 --- a/content/posts/2012-11-22-customac.md +++ b/content/posts/2012/2012-11-22-customac.md @@ -1,194 +1,194 @@ -+++ -date = "2012-11-22" -title = "CustoMac" -tags = ["osx", "hacks", "customac", "osx86"] -slug = "customac" -+++ - -Ever since Apple decided to put Intel processors in their Macs there have been attempts by enthusiasts to run Mac OS X on commodity hardware – with mixed results. - -The key to installing Mac OS X on a non-Mac computer is using the right hardware. If your hardware is a close to Apple kit as possible, you have the best chance to succeed. - -The so-called *Hackintosh* community has come a long way the past few years in making it easy for "normal people" to install Mac OS X on their _PC_. - -Since I was tired of using Debian Linux on my Desktop, dual booting to Windows to play the occasional game of _World of Warcraft_, I decided to give installing Mac OS X a try. But there was a problem. - -## The hardware - -My current PC is powered by an AMD processor (AMD Phenom II X6 1055T, to be precise). Simply put, installing Mac OS X on an AMD cpu is not going to work. - -So, the first thing I did was go over to the [OSx86 Project Hardware Compatibility List][2] and see what hardware is most compatible with Mac OS X 1.8.2 (the most recent version of OS X at this time). - -I already knew I'd need a shiny new Intel CPU, and thus also a new motherboard. - -## Choosing a CPU - -Choosing a CPU for your CustoMac is not very difficult, because you are limited to Intel. Since the release of the new MacBooks Apple officially supports the [Ivy Bridge][1] architecture, which means about a 50% lower power consumption and a 5-15% speed increase ([link][1]). - -The main candidates were: - -* Intel i5 3570 -* Intel i5 3570K -* Intel i7 3770K - -I won't go into to too much detail here, but I chose the _Intel i5 3570_. - -The i7 offers [Hyper Threading][3] at a price bump of about € 100,-. For me, this was not worth the money. - -Then there's the choice between the _3570_ or the _3570K_. The 'K' version has less features, but is _unlocked_, allow it to be easily over-clocked to higher speeds. - -The price difference between the _3570_ and the _3570_ are minimal, but I'm not planning to over-clock my CPU, so I went for the slightly cheaper _Intel i5 3570_ processor. - -## Choosing a motherboard - -Next came a more difficult decision. The motherboard. Again, the [Hardware Compatibility List][2] was a great help here. In the end I chose the _Gigabyte Z77-DS3H_. - -The pro's of this board are that it's well supported by Mac OS X and the OSx86 community. This board is special because it features Gigabyte's 3D UEFI Bios. This bios would make it easy to install Mac OS X _untouched_ on your machine. - -I didn't end up using this UEFI feature, but nonetheless, support for this board is incredible. - -## The full hardware list - -So, recycling other parts of my current _PC_ I build the following CustoMac configuration: - -* Gigabyte Z77-DS3H Motherboard ([But at Amazon][9]) -* Intel i5 3570 CPU @3.4Ghz ([Buy at Amazon][8]) -* 16GB RAM at 1333Mhz -* 1x 120 GB OCZ Agility 3 SSD -* 1x 1TB Western Digital HD -* 1x 2TB Western Digital HD -* XFX ATI Radeon HD 6870 1GB ([Buy at Amazon][10]) - -_Note 1: The above Amazon links are affiliate links._ - -_Note 2: I could have upgraded my memory to 1600Mhz units, which would be faster. But I have no use for the old memory, so I chose to re-use it for now._ - -## The preparation - -Before you get started, you should prepare an installation USB drive on another Mac. You'll need at least 8GB of space on the drive. - -* Buy Mountain Lion from the App Store on you Mac and download the installer. If you already purchased Mountain Lion, re-download it. -* Download [UniBeast][4] for Mountain Lion and follow step 1 and 2 from [this guide][5]. - -At this point you have a bootable USB drive with the Mountain Lion install on it. - -To prepare the actual installation, remove any devices you don't need, like extra hard drivers, DVD/BluRay drives, etc. In my case I also pulled out the ATI 6870 and used the onboard Intel HD Graphics during installation. - -Plug your USB drive into a USB 2.0 (black, not blue) port on the motherboard. Make sure to use one of the ports on the back of your computer, those are directly attached to the motherboard and have the greatest chance of succes. - -Now, boot up the computer and enter the BIOS. There are two important changes you need to make. - -* Set SATA to `AHCI` mode. -* Disable `VT-d`. - -Then select the USB drive as the bootable device and boot. - -## Booting the installer - -You'll see the UniBeast boot screen which show a 'USB' option (and possibly other, depending on what's on your disks). Choose 'USB' - but don't press `ENTER` just yet. Instead, type `-x`, which will show up on the screen. Then, press `ENTER`. - -After a few minutes you should have the Mac OS X Installer in front of you. Go ahead, install this baby. - -## Notes on Fusion drive - -It's possible to create a CustoMac Fusion Drive using an SSD and regular harddisk. - -When you're in the installer, choose 'Terminal' to open a terminal window and follow the steps in [this fusion drive guide][6]. - -I was able to create and install Mac OS X on a Fusion Drive without problems. The only knack was that the custom bootloader you need is not Fusion Drive aware, which makes it difficult to use. - -In the end I decided to not use a Fusion drive setup, and just install everything on the SSD. - -## Completing the installation - -Now comes the tricky part. The installation is done and you're CustoMac wants to reboot. Let it, but leave the USB drive connected. - -Your machine will boot up with the same boot menu as before, but instead of 'USB' you should now be able to select 'Macintosh HD'. - -Select that, enter `-x` followed by `ENTER`. - -You'll now be taken through the final steps of installation, like setting up iCloud and creating a user account. - -When finished, you should be on your new Mac desktop. - -## Installing custom kexts - -Now, your CustoMac can only boot with the USB drive. Let's change that by installing a bootloader and some kernel extensions. - -* Download [MultiBeast][4] for Mountain Lion. -* Run the installer and select the following options: -** UserDSDT or DSDT-Free Installation -** Miscellaneous => FakeSMC -** Audio => Realtek ALC8xx => Without DSDT => Latest version for ALC8887/888b. -** Network => maolj's AtherosL1cEthernet -** Disk => TRIM fix for 1.8.1+ -** Bootloaders => Chimera - -That's all. Install that stuff. Now, you should be able to reboot your CustoMac and boot it without the USB drive. - -If things don't work out (like a black or white screen, kernel panics, whatever), just plugin your USB drive again, boot from it and select your 'Macintosh HD'. - -## Graphics - -At this point, you should have a working CustoMac with sound and network working. The only thing missing is a proper graphics card. - -You'll need to make some tweaks to the chameleon plist file. Then shutdown your computer and install the graphics card. - -_Note: this works for my XFX ATI Radeon HD 6870 card. There may be subtle differences for different version and brands. Just use the Google to find hints, boot with the USB drive to get to your system and make updates as needed._ - -In `/Extra/org.chameleon.Boot.plist` make sure you have the following entries: - -``` xml -AtiConfig -Duckweed -AtiPorts -5 -Graphics Mode -1920x1080x32 -GraphicsEnabler -Yes -PciRoot -1 -``` - -Depending on which slot you used for your graphics card, you may have to set `PciRoot` to `0`. - -I also had to add `npci=0x2000` to `Kernel Flags`, but you may or may not need it. - -``` xml -Kernel Flags -``` - -## Boot up! - -Now, reboot one last time and everything should go smoothly. - -If your system comes up without any troubles, start attaching those others disks and drives you had disconnected during the installation. There shouldn't be any issues here. - -## You're done! - -Congratulations. You now have a CustoMac! - -Keep in mind that you should not blindly install any update you see. Installing an update my change the bootloader or change kernel extensions that break your system. - -A good tip is to create a full disk image of your SSD using a tool like [Super Duper][7]. In case of shit hitting the fan after an update, you can easily restore your disk to working order. - -In my case, I've attached an old 500GB drive to store this disk image. It works great. - -## Shiny and fast! - -Just as a side-note, my CustoMac is blazingly fast. It's the combination of the fast _Ivy Bridge_ architecture, the i5 processor, and the SSD. - -I've measured boot-up time from pressing the power button to the Mac OS X login screen at about 11 seconds. - -[1]: http://en.wikipedia.org/wiki/Ivy_Bridge_%28microarchitecture%29 -[2]: http://wiki.osx86project.org/wiki/index.php/HCL_10.8.2 -[3]: http://en.wikipedia.org/wiki/Hyper-threading -[4]: http://www.tonymacx86.com/downloads -[5]: http://tonymacx86.blogspot.nl/2011/10/unibeast-install-mac-os-x-lion-using.html -[6]: http://jollyjinx.tumblr.com/post/34638496292/fusion-drive-on-older-macs-yes-since-apple-has -[7]: http://www.shirt-pocket.com/SuperDuper/SuperDuperDescription.html -[8]: http://www.amazon.com/gp/product/B0087EVHTE/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B0087EVHTE&linkCode=as2&tag=ariejannet-20 -[9]: http://www.amazon.com/gp/product/B007R21JWC/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B007R21JWC&linkCode=as2&tag=ariejannet-20 -[10]: http://www.amazon.com/gp/product/B0047ZH7GE/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B0047ZH7GE&linkCode=as2&tag=ariejannet-20 - ++++ +date = "2012-11-22" +title = "CustoMac" +tags = ["osx", "hacks", "customac", "osx86"] +slug = "customac" ++++ + +Ever since Apple decided to put Intel processors in their Macs there have been attempts by enthusiasts to run Mac OS X on commodity hardware – with mixed results. + +The key to installing Mac OS X on a non-Mac computer is using the right hardware. If your hardware is a close to Apple kit as possible, you have the best chance to succeed. + +The so-called *Hackintosh* community has come a long way the past few years in making it easy for "normal people" to install Mac OS X on their _PC_. + +Since I was tired of using Debian Linux on my Desktop, dual booting to Windows to play the occasional game of _World of Warcraft_, I decided to give installing Mac OS X a try. But there was a problem. + +## The hardware + +My current PC is powered by an AMD processor (AMD Phenom II X6 1055T, to be precise). Simply put, installing Mac OS X on an AMD cpu is not going to work. + +So, the first thing I did was go over to the [OSx86 Project Hardware Compatibility List][2] and see what hardware is most compatible with Mac OS X 1.8.2 (the most recent version of OS X at this time). + +I already knew I'd need a shiny new Intel CPU, and thus also a new motherboard. + +## Choosing a CPU + +Choosing a CPU for your CustoMac is not very difficult, because you are limited to Intel. Since the release of the new MacBooks Apple officially supports the [Ivy Bridge][1] architecture, which means about a 50% lower power consumption and a 5-15% speed increase ([link][1]). + +The main candidates were: + +* Intel i5 3570 +* Intel i5 3570K +* Intel i7 3770K + +I won't go into to too much detail here, but I chose the _Intel i5 3570_. + +The i7 offers [Hyper Threading][3] at a price bump of about € 100,-. For me, this was not worth the money. + +Then there's the choice between the _3570_ or the _3570K_. The 'K' version has less features, but is _unlocked_, allow it to be easily over-clocked to higher speeds. + +The price difference between the _3570_ and the _3570_ are minimal, but I'm not planning to over-clock my CPU, so I went for the slightly cheaper _Intel i5 3570_ processor. + +## Choosing a motherboard + +Next came a more difficult decision. The motherboard. Again, the [Hardware Compatibility List][2] was a great help here. In the end I chose the _Gigabyte Z77-DS3H_. + +The pro's of this board are that it's well supported by Mac OS X and the OSx86 community. This board is special because it features Gigabyte's 3D UEFI Bios. This bios would make it easy to install Mac OS X _untouched_ on your machine. + +I didn't end up using this UEFI feature, but nonetheless, support for this board is incredible. + +## The full hardware list + +So, recycling other parts of my current _PC_ I build the following CustoMac configuration: + +* Gigabyte Z77-DS3H Motherboard ([But at Amazon][9]) +* Intel i5 3570 CPU @3.4Ghz ([Buy at Amazon][8]) +* 16GB RAM at 1333Mhz +* 1x 120 GB OCZ Agility 3 SSD +* 1x 1TB Western Digital HD +* 1x 2TB Western Digital HD +* XFX ATI Radeon HD 6870 1GB ([Buy at Amazon][10]) + +_Note 1: The above Amazon links are affiliate links._ + +_Note 2: I could have upgraded my memory to 1600Mhz units, which would be faster. But I have no use for the old memory, so I chose to re-use it for now._ + +## The preparation + +Before you get started, you should prepare an installation USB drive on another Mac. You'll need at least 8GB of space on the drive. + +* Buy Mountain Lion from the App Store on you Mac and download the installer. If you already purchased Mountain Lion, re-download it. +* Download [UniBeast][4] for Mountain Lion and follow step 1 and 2 from [this guide][5]. + +At this point you have a bootable USB drive with the Mountain Lion install on it. + +To prepare the actual installation, remove any devices you don't need, like extra hard drivers, DVD/BluRay drives, etc. In my case I also pulled out the ATI 6870 and used the onboard Intel HD Graphics during installation. + +Plug your USB drive into a USB 2.0 (black, not blue) port on the motherboard. Make sure to use one of the ports on the back of your computer, those are directly attached to the motherboard and have the greatest chance of succes. + +Now, boot up the computer and enter the BIOS. There are two important changes you need to make. + +* Set SATA to `AHCI` mode. +* Disable `VT-d`. + +Then select the USB drive as the bootable device and boot. + +## Booting the installer + +You'll see the UniBeast boot screen which show a 'USB' option (and possibly other, depending on what's on your disks). Choose 'USB' - but don't press `ENTER` just yet. Instead, type `-x`, which will show up on the screen. Then, press `ENTER`. + +After a few minutes you should have the Mac OS X Installer in front of you. Go ahead, install this baby. + +## Notes on Fusion drive + +It's possible to create a CustoMac Fusion Drive using an SSD and regular harddisk. + +When you're in the installer, choose 'Terminal' to open a terminal window and follow the steps in [this fusion drive guide][6]. + +I was able to create and install Mac OS X on a Fusion Drive without problems. The only knack was that the custom bootloader you need is not Fusion Drive aware, which makes it difficult to use. + +In the end I decided to not use a Fusion drive setup, and just install everything on the SSD. + +## Completing the installation + +Now comes the tricky part. The installation is done and you're CustoMac wants to reboot. Let it, but leave the USB drive connected. + +Your machine will boot up with the same boot menu as before, but instead of 'USB' you should now be able to select 'Macintosh HD'. + +Select that, enter `-x` followed by `ENTER`. + +You'll now be taken through the final steps of installation, like setting up iCloud and creating a user account. + +When finished, you should be on your new Mac desktop. + +## Installing custom kexts + +Now, your CustoMac can only boot with the USB drive. Let's change that by installing a bootloader and some kernel extensions. + +* Download [MultiBeast][4] for Mountain Lion. +* Run the installer and select the following options: +** UserDSDT or DSDT-Free Installation +** Miscellaneous => FakeSMC +** Audio => Realtek ALC8xx => Without DSDT => Latest version for ALC8887/888b. +** Network => maolj's AtherosL1cEthernet +** Disk => TRIM fix for 1.8.1+ +** Bootloaders => Chimera + +That's all. Install that stuff. Now, you should be able to reboot your CustoMac and boot it without the USB drive. + +If things don't work out (like a black or white screen, kernel panics, whatever), just plugin your USB drive again, boot from it and select your 'Macintosh HD'. + +## Graphics + +At this point, you should have a working CustoMac with sound and network working. The only thing missing is a proper graphics card. + +You'll need to make some tweaks to the chameleon plist file. Then shutdown your computer and install the graphics card. + +_Note: this works for my XFX ATI Radeon HD 6870 card. There may be subtle differences for different version and brands. Just use the Google to find hints, boot with the USB drive to get to your system and make updates as needed._ + +In `/Extra/org.chameleon.Boot.plist` make sure you have the following entries: + +``` xml +AtiConfig +Duckweed +AtiPorts +5 +Graphics Mode +1920x1080x32 +GraphicsEnabler +Yes +PciRoot +1 +``` + +Depending on which slot you used for your graphics card, you may have to set `PciRoot` to `0`. + +I also had to add `npci=0x2000` to `Kernel Flags`, but you may or may not need it. + +``` xml +Kernel Flags +``` + +## Boot up! + +Now, reboot one last time and everything should go smoothly. + +If your system comes up without any troubles, start attaching those others disks and drives you had disconnected during the installation. There shouldn't be any issues here. + +## You're done! + +Congratulations. You now have a CustoMac! + +Keep in mind that you should not blindly install any update you see. Installing an update my change the bootloader or change kernel extensions that break your system. + +A good tip is to create a full disk image of your SSD using a tool like [Super Duper][7]. In case of shit hitting the fan after an update, you can easily restore your disk to working order. + +In my case, I've attached an old 500GB drive to store this disk image. It works great. + +## Shiny and fast! + +Just as a side-note, my CustoMac is blazingly fast. It's the combination of the fast _Ivy Bridge_ architecture, the i5 processor, and the SSD. + +I've measured boot-up time from pressing the power button to the Mac OS X login screen at about 11 seconds. + +[1]: http://en.wikipedia.org/wiki/Ivy_Bridge_%28microarchitecture%29 +[2]: http://wiki.osx86project.org/wiki/index.php/HCL_10.8.2 +[3]: http://en.wikipedia.org/wiki/Hyper-threading +[4]: http://www.tonymacx86.com/downloads +[5]: http://tonymacx86.blogspot.nl/2011/10/unibeast-install-mac-os-x-lion-using.html +[6]: http://jollyjinx.tumblr.com/post/34638496292/fusion-drive-on-older-macs-yes-since-apple-has +[7]: http://www.shirt-pocket.com/SuperDuper/SuperDuperDescription.html +[8]: http://www.amazon.com/gp/product/B0087EVHTE/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B0087EVHTE&linkCode=as2&tag=ariejannet-20 +[9]: http://www.amazon.com/gp/product/B007R21JWC/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B007R21JWC&linkCode=as2&tag=ariejannet-20 +[10]: http://www.amazon.com/gp/product/B0047ZH7GE/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B0047ZH7GE&linkCode=as2&tag=ariejannet-20 + diff --git a/content/posts/2012-11-29-binary-debugging-with-git-bisect.md b/content/posts/2012/2012-11-29-binary-debugging-with-git-bisect.md similarity index 97% rename from content/posts/2012-11-29-binary-debugging-with-git-bisect.md rename to content/posts/2012/2012-11-29-binary-debugging-with-git-bisect.md index a67bfbf..b179d3b 100644 --- a/content/posts/2012-11-29-binary-debugging-with-git-bisect.md +++ b/content/posts/2012/2012-11-29-binary-debugging-with-git-bisect.md @@ -1,143 +1,143 @@ -+++ -date = "2012-11-29" -title = "Binary debugging with git bisect" -tags = ["git", "bisect"] -slug = "binary-debugging-with-git-bisect" -+++ - -Part of resolving a bug is finding where and when that bug was introduced into your code. Not so much for blaming a specific person, but more for an understanding of how and maybe why the bug was introduced; and more over which versions of your app are affected. - -Most of the time the bug was recently introduced and your CI notified you that stuff has been broken. - -In order to find out when, how and by whom the build was broken, you'll have to dig into your git history and run your specs to see if they pass or not. - -Running your specs for every commit in your history manually is very time consuming and boring. Luckily there are better ways, using plain old git. - -## Binary search - -Before I dive into git, it's important you understand how binary search works. If you already know this stuff, skip right to the next section. - -You have a sorted array. This means there is some order to the elements you have. Presume you have an array of ints: - -``` ruby -a = [1, 3, 4, 7, 33, 42, 54, 76, 89, 91] -``` - -Now, we want to find the position (`n`) of `7` in this array using binary search so that `a[n] == 7`. - -Binary search uses a divide and conquer strategy. You split the array in the middle. We have 10 elements, so a logical place would be to split the array at position `n = 5`, which has the value `42`. - -Comparing `7 <=> 42` tells us that, because we have an ordered array, the value `7` should be in the first half of the array. - -We can ignore the right half of the array for searching, and repeat this step for the left part, specifically: - -``` ruby -[1, 3, 4, 7, 33] -``` - -So, let's split this part up again. We get `4`. This is less than `7`, so if we continue looking we should take the right part. - -``` ruby -[7, 33] -``` - -Okay, again, we continue our search. We know have to split the array one way or the other, and we end up picking `n = 4`. We hit `33`. Surely the value of `7` must be on the left part of this. - -_Note that although I don't show the whole array, I'm still using the index positions for the entire `a` array._ - -``` ruby -[7] -``` - -Now, there's not much to pick for us. This is 7. Right here at `n = 3`. Done! - -Notice that the last step does not involve checking the value of the last element. We only have 1 element left, so we're finished. - -If we had been looking for a value of 18, we would have also found `n = 3`. This means that we can search for non-existing values, which then return the index right before where that number should be inserted. This works because the array was ordered, so we can safely make such assumptions. Nice, huh? - -## How does binary search relate to finding bugs? - -Well, in the example above we were looking for an integer value. The test we use to evaluate is simple: - -``` ruby -value <=> a[n] -``` - -When we want to find the commit that broke our build we need a more clever way of comparing values. - -This is where your test suite comes in. You have a failing spec now, so basically we're looking for the point in git history where that spec failed for the first time. - -## Git bisect - -Because it's not feasible to do a linear search over your entire commit history, we'll have to start by marking a _good_ and a _bad_ commit. - -First we'll have to find a location in your git history where you know the app did not exhibit this bug. - -More than likely, this place is your last stable release. If you used `git tag` to tag your release, you should be able to find out quickly if that release contains the bug. - -``` shell -git checkout v1.2.1 -rspec spec/features/fancy_spec.rb -=> 0 failures -``` - -Good. We now our latest commit was broken, so let's get started with that binary search! - -You don't have to keep track of the git history and binary search position all by yourself: git does this for you. All you have to do is compare each commit that is presented to you with an expected result. E.g. does the `fancy_spec.rb` spec pass or not? - -## Bisecting steps - -First, let git know you want to do a binary search. - -``` shell -git bisect start -``` - -Next, let git know which commit is good, and which one is bad. - -``` shell -git bisect good v1.2.1 -git bisect bad e8ab31 -``` - -Git will respond with something like this: - -``` shell -Bisecting: 19 revisions left to test after this (roughly 4 steps) -[0e70ee6aefe428fa897ec7e48273c3fe4d0bf7fb] Did some funky stuff in `config/application.rb`. -``` - -Git has determined that commit `0e70ee` is right in between `v1.2.1` and `ebab31`. Check if this revision is broken and report back to git. - -``` shell -rspec spec/features/fancy_spec.rb -> 1 failure -git bisect bad -``` - -And git will respond: - -``` shell -Bisecting: 9 revisions left to test after this (roughly 3 steps) -``` - -You can continue this until git tells you the commit that first broke this spec. - -When you're done bisecting (or if you just feel like doing something else), just tell git: - -``` shell -git bisect reset -``` - -## Usage in the field - -Git bisect is a very powerful tool to find specific points in your code. - -In this example we were looking for a commit that broke a specific test. You can look for all kinds of things: - -* When did the layout on that page break? -* At what point did we upgrade that gem to a buggy release? -* Who added this ugly piece of code?! - -Doing a binary search over your git history is a fast and efficient way of finding these kind of things out. - ++++ +date = "2012-11-29" +title = "Binary debugging with git bisect" +tags = ["git", "bisect"] +slug = "binary-debugging-with-git-bisect" ++++ + +Part of resolving a bug is finding where and when that bug was introduced into your code. Not so much for blaming a specific person, but more for an understanding of how and maybe why the bug was introduced; and more over which versions of your app are affected. + +Most of the time the bug was recently introduced and your CI notified you that stuff has been broken. + +In order to find out when, how and by whom the build was broken, you'll have to dig into your git history and run your specs to see if they pass or not. + +Running your specs for every commit in your history manually is very time consuming and boring. Luckily there are better ways, using plain old git. + +## Binary search + +Before I dive into git, it's important you understand how binary search works. If you already know this stuff, skip right to the next section. + +You have a sorted array. This means there is some order to the elements you have. Presume you have an array of ints: + +``` ruby +a = [1, 3, 4, 7, 33, 42, 54, 76, 89, 91] +``` + +Now, we want to find the position (`n`) of `7` in this array using binary search so that `a[n] == 7`. + +Binary search uses a divide and conquer strategy. You split the array in the middle. We have 10 elements, so a logical place would be to split the array at position `n = 5`, which has the value `42`. + +Comparing `7 <=> 42` tells us that, because we have an ordered array, the value `7` should be in the first half of the array. + +We can ignore the right half of the array for searching, and repeat this step for the left part, specifically: + +``` ruby +[1, 3, 4, 7, 33] +``` + +So, let's split this part up again. We get `4`. This is less than `7`, so if we continue looking we should take the right part. + +``` ruby +[7, 33] +``` + +Okay, again, we continue our search. We know have to split the array one way or the other, and we end up picking `n = 4`. We hit `33`. Surely the value of `7` must be on the left part of this. + +_Note that although I don't show the whole array, I'm still using the index positions for the entire `a` array._ + +``` ruby +[7] +``` + +Now, there's not much to pick for us. This is 7. Right here at `n = 3`. Done! + +Notice that the last step does not involve checking the value of the last element. We only have 1 element left, so we're finished. + +If we had been looking for a value of 18, we would have also found `n = 3`. This means that we can search for non-existing values, which then return the index right before where that number should be inserted. This works because the array was ordered, so we can safely make such assumptions. Nice, huh? + +## How does binary search relate to finding bugs? + +Well, in the example above we were looking for an integer value. The test we use to evaluate is simple: + +``` ruby +value <=> a[n] +``` + +When we want to find the commit that broke our build we need a more clever way of comparing values. + +This is where your test suite comes in. You have a failing spec now, so basically we're looking for the point in git history where that spec failed for the first time. + +## Git bisect + +Because it's not feasible to do a linear search over your entire commit history, we'll have to start by marking a _good_ and a _bad_ commit. + +First we'll have to find a location in your git history where you know the app did not exhibit this bug. + +More than likely, this place is your last stable release. If you used `git tag` to tag your release, you should be able to find out quickly if that release contains the bug. + +``` shell +git checkout v1.2.1 +rspec spec/features/fancy_spec.rb +=> 0 failures +``` + +Good. We now our latest commit was broken, so let's get started with that binary search! + +You don't have to keep track of the git history and binary search position all by yourself: git does this for you. All you have to do is compare each commit that is presented to you with an expected result. E.g. does the `fancy_spec.rb` spec pass or not? + +## Bisecting steps + +First, let git know you want to do a binary search. + +``` shell +git bisect start +``` + +Next, let git know which commit is good, and which one is bad. + +``` shell +git bisect good v1.2.1 +git bisect bad e8ab31 +``` + +Git will respond with something like this: + +``` shell +Bisecting: 19 revisions left to test after this (roughly 4 steps) +[0e70ee6aefe428fa897ec7e48273c3fe4d0bf7fb] Did some funky stuff in `config/application.rb`. +``` + +Git has determined that commit `0e70ee` is right in between `v1.2.1` and `ebab31`. Check if this revision is broken and report back to git. + +``` shell +rspec spec/features/fancy_spec.rb +> 1 failure +git bisect bad +``` + +And git will respond: + +``` shell +Bisecting: 9 revisions left to test after this (roughly 3 steps) +``` + +You can continue this until git tells you the commit that first broke this spec. + +When you're done bisecting (or if you just feel like doing something else), just tell git: + +``` shell +git bisect reset +``` + +## Usage in the field + +Git bisect is a very powerful tool to find specific points in your code. + +In this example we were looking for a commit that broke a specific test. You can look for all kinds of things: + +* When did the layout on that page break? +* At what point did we upgrade that gem to a buggy release? +* Who added this ugly piece of code?! + +Doing a binary search over your git history is a fast and efficient way of finding these kind of things out. + diff --git a/content/posts/2012-12-18-instagram-governments-and-cypherpunks.md b/content/posts/2012/2012-12-18-instagram-governments-and-cypherpunks.md similarity index 98% rename from content/posts/2012-12-18-instagram-governments-and-cypherpunks.md rename to content/posts/2012/2012-12-18-instagram-governments-and-cypherpunks.md index 2258d81..da606cb 100644 --- a/content/posts/2012-12-18-instagram-governments-and-cypherpunks.md +++ b/content/posts/2012/2012-12-18-instagram-governments-and-cypherpunks.md @@ -4,94 +4,94 @@ title = "Instagram, Governments and Cypherpunks" tags = ["rant", "cypherpunk", "privacy", "instagram"] slug = "instagram-governments-and-cypherpunks" +++ -The whole internet collectively fell over Instagram earlier this week when they released their new _Terms of Service_. - -> Some or all of the Service may be supported by advertising revenue. To help us deliver interesting paid or sponsored content or promotions, you agree that a business or other entity may pay us to display your username, likeness, photos (along with any associated metadata), and/or actions you take, in connection with paid or sponsored content or promotions, without any compensation to you. - -Today [Instagram officially responded][1] to all the screaming and shouting, trying to control the damage. - -> From the start, Instagram was created to become a business. - -Well, that was unexpected. It's the same with Facebook, Twitter, Gmail, Hotmail, etc. All these services are here for you to use for free - awesome! - -But nobody ever got rich from giving stuff away for free, and these are businesses we're talking about. - -Let's see how this works over at Facebook. - -## Exhibit A: Facebook - -Facebook is a good example of how you are the product being sold. We all know Facebook tries to show you ads that you are likely interested in. Based on what you put in your profile advertisers can target specific audiences. - -That might sound all well and good to you, but did you also know that your friends might see a _sponsored_ post in their newsfeed? And that that _sponsored_ post appears as if it's one posted by _you_? - -![Facebook sponsored post](https://s3-eu-west-1.amazonaws.com/ariejannet/images/related-post.png) - -Here you see a post by a friend of mine who apparently likes some mobile company's ad. They didn't like this add. I asked them. - -So basically Facebook and an advertiser are using you, your name and your profile picture to promote an advertisement to one of your friends. - -## Exhibit B: Google - -Another example, more in line with Facebook, is Google. All those free tools: Search, Gmail, Google+, Analytics, Web Master Tools, maps. They are all geared towards either exposing ads to you, or gathering data on you to expose more focussed ads. - -The plus side here, I would say, is that Google actually delivers usable services, like search, mail, calendars and such. But still, look at the boatloads of money Google is making selling ads based on your private details and online behaviour. - -## Exhibit C: Twitter - -Twitter is a company that has struggled for a long time to find a way to monetize itself. Hopes were high that they would find a new an innovative way, but they have not. - -It remains to be seen what's going to happen exactly with twitter, but we can all assume that our tweets are being analyzed and that Twitter will do anything to sell you to their advertisers. - -## Exhibit D: Instagram - -To come back to Instagram, they're in the same boat as Twitter and Facebook. - -They have been growing their user base for quite some time now and now comes the time to move in and cash on all those users. - -The new terms of service should not come as a surprise. - -Instagram wants to use your data to match you up with advertisers and it even wants to show ads endorsed by you, just like Facebook already does. - -## So what's happening out there? - -Social Media are nice, they connect people and can start revolutions. But that is not why those media exist. They are marketing and data mining platforms on a massive scale. - -Have you ever wondered why social media companies get multi million dollar investments? Because with a huge, world-wide user base, there is a huge advertising potential. - -_If you are not buying a product or service, but are receiving one for free, then you are the product or service begin sold._ - -I think that companies like Facebook and Instagram are wading in a gray area of privacy. Their practices may be perfectly legal, but they _are_ ethically questionable. - -## On government spying and eavesdropping - -You might sometimes worry about governments eavesdropping and keeping tabs on innocent citizens – and you should. - -If you look at the sheer amount of data social media gather on you, imagine what kind of data a government agency with the proper tools and hardware can do. - -But the issue is not really that companies and governments are gathering data - you are feeding it to them with every status update and photo you upload to the internet. With every email you sent. - -So, what's to be done? - -## Cypherpunks to the rescue? - -Now, I won't claim to know a whole lot about cypherpunks and the crypto wars, but these people have fought (and still are) fighting for our digital rights and freedom. - -We are collectively giving away our personal data to companies and governments and most of the time we don't even know it. But then some image sharing company changes its terms that will allow them to display adds alongside your name and we freak out. - -Here's quite from the Cypherpunks manifesto: - -> Privacy is necessary for an open society in the electronic age. ... We cannot expect governments, corporations, or other large, faceless organizations to grant us privacy ... We must defend our own privacy if we expect to have any. ... Cypherpunks write code. We know that someone has to write software to defend privacy, and ... we're going to write it. - -To be clear, I'm not a cypherpunk by any means. Here's a snippet from Wired magazine, 1993: - -> The people in this room [cypherpunks] hope for a world where an individual's informational footprints -- everything from an opinion on abortion to the medical record of an actual abortion -- can be traced only if the individual involved chooses to reveal them; - -And this is where the problem lies. Yesterday Will Wheaton, of Star Trek fame, [wrote about][2] this as well. - -Will has a great point that we've come to a point where it's okay that somebody else shares your personal details with a third party on the internet – without your knowledge, without your consent. And there is nothing you can do about it. - -I'm not sure about you, but this sure frightens me. - -[1]: http://blog.instagram.com/post/38252135408/thank-you-and-were-listening +The whole internet collectively fell over Instagram earlier this week when they released their new _Terms of Service_. + +> Some or all of the Service may be supported by advertising revenue. To help us deliver interesting paid or sponsored content or promotions, you agree that a business or other entity may pay us to display your username, likeness, photos (along with any associated metadata), and/or actions you take, in connection with paid or sponsored content or promotions, without any compensation to you. + +Today [Instagram officially responded][1] to all the screaming and shouting, trying to control the damage. + +> From the start, Instagram was created to become a business. + +Well, that was unexpected. It's the same with Facebook, Twitter, Gmail, Hotmail, etc. All these services are here for you to use for free - awesome! + +But nobody ever got rich from giving stuff away for free, and these are businesses we're talking about. + +Let's see how this works over at Facebook. + +## Exhibit A: Facebook + +Facebook is a good example of how you are the product being sold. We all know Facebook tries to show you ads that you are likely interested in. Based on what you put in your profile advertisers can target specific audiences. + +That might sound all well and good to you, but did you also know that your friends might see a _sponsored_ post in their newsfeed? And that that _sponsored_ post appears as if it's one posted by _you_? + +![Facebook sponsored post](https://s3-eu-west-1.amazonaws.com/ariejannet/images/related-post.png) + +Here you see a post by a friend of mine who apparently likes some mobile company's ad. They didn't like this add. I asked them. + +So basically Facebook and an advertiser are using you, your name and your profile picture to promote an advertisement to one of your friends. + +## Exhibit B: Google + +Another example, more in line with Facebook, is Google. All those free tools: Search, Gmail, Google+, Analytics, Web Master Tools, maps. They are all geared towards either exposing ads to you, or gathering data on you to expose more focussed ads. + +The plus side here, I would say, is that Google actually delivers usable services, like search, mail, calendars and such. But still, look at the boatloads of money Google is making selling ads based on your private details and online behaviour. + +## Exhibit C: Twitter + +Twitter is a company that has struggled for a long time to find a way to monetize itself. Hopes were high that they would find a new an innovative way, but they have not. + +It remains to be seen what's going to happen exactly with twitter, but we can all assume that our tweets are being analyzed and that Twitter will do anything to sell you to their advertisers. + +## Exhibit D: Instagram + +To come back to Instagram, they're in the same boat as Twitter and Facebook. + +They have been growing their user base for quite some time now and now comes the time to move in and cash on all those users. + +The new terms of service should not come as a surprise. + +Instagram wants to use your data to match you up with advertisers and it even wants to show ads endorsed by you, just like Facebook already does. + +## So what's happening out there? + +Social Media are nice, they connect people and can start revolutions. But that is not why those media exist. They are marketing and data mining platforms on a massive scale. + +Have you ever wondered why social media companies get multi million dollar investments? Because with a huge, world-wide user base, there is a huge advertising potential. + +_If you are not buying a product or service, but are receiving one for free, then you are the product or service begin sold._ + +I think that companies like Facebook and Instagram are wading in a gray area of privacy. Their practices may be perfectly legal, but they _are_ ethically questionable. + +## On government spying and eavesdropping + +You might sometimes worry about governments eavesdropping and keeping tabs on innocent citizens – and you should. + +If you look at the sheer amount of data social media gather on you, imagine what kind of data a government agency with the proper tools and hardware can do. + +But the issue is not really that companies and governments are gathering data - you are feeding it to them with every status update and photo you upload to the internet. With every email you sent. + +So, what's to be done? + +## Cypherpunks to the rescue? + +Now, I won't claim to know a whole lot about cypherpunks and the crypto wars, but these people have fought (and still are) fighting for our digital rights and freedom. + +We are collectively giving away our personal data to companies and governments and most of the time we don't even know it. But then some image sharing company changes its terms that will allow them to display adds alongside your name and we freak out. + +Here's quite from the Cypherpunks manifesto: + +> Privacy is necessary for an open society in the electronic age. ... We cannot expect governments, corporations, or other large, faceless organizations to grant us privacy ... We must defend our own privacy if we expect to have any. ... Cypherpunks write code. We know that someone has to write software to defend privacy, and ... we're going to write it. + +To be clear, I'm not a cypherpunk by any means. Here's a snippet from Wired magazine, 1993: + +> The people in this room [cypherpunks] hope for a world where an individual's informational footprints -- everything from an opinion on abortion to the medical record of an actual abortion -- can be traced only if the individual involved chooses to reveal them; + +And this is where the problem lies. Yesterday Will Wheaton, of Star Trek fame, [wrote about][2] this as well. + +Will has a great point that we've come to a point where it's okay that somebody else shares your personal details with a third party on the internet – without your knowledge, without your consent. And there is nothing you can do about it. + +I'm not sure about you, but this sure frightens me. + +[1]: http://blog.instagram.com/post/38252135408/thank-you-and-were-listening [2]: https://plus.google.com/108176814619778619437/posts/3o79SJWv4kG diff --git a/content/posts/2013-03-08-review-commits-in-your-feature-branch.md b/content/posts/2013/2013-03-08-review-commits-in-your-feature-branch.md similarity index 100% rename from content/posts/2013-03-08-review-commits-in-your-feature-branch.md rename to content/posts/2013/2013-03-08-review-commits-in-your-feature-branch.md diff --git a/content/posts/2013-03-25-automated-nanoc-deployments.md b/content/posts/2013/2013-03-25-automated-nanoc-deployments.md similarity index 100% rename from content/posts/2013-03-25-automated-nanoc-deployments.md rename to content/posts/2013/2013-03-25-automated-nanoc-deployments.md diff --git a/content/posts/2013-03-26-i-am-here-for-an-argument.md b/content/posts/2013/2013-03-26-i-am-here-for-an-argument.md similarity index 100% rename from content/posts/2013-03-26-i-am-here-for-an-argument.md rename to content/posts/2013/2013-03-26-i-am-here-for-an-argument.md diff --git a/content/posts/2013-05-21-early-birds.md b/content/posts/2013/2013-05-21-early-birds.md similarity index 100% rename from content/posts/2013-05-21-early-birds.md rename to content/posts/2013/2013-05-21-early-birds.md diff --git a/content/posts/2013-05-23-divide-and-conquer.md b/content/posts/2013/2013-05-23-divide-and-conquer.md similarity index 100% rename from content/posts/2013-05-23-divide-and-conquer.md rename to content/posts/2013/2013-05-23-divide-and-conquer.md diff --git a/content/posts/2013-10-31-deploying-with-git-deploy.md b/content/posts/2013/2013-10-31-deploying-with-git-deploy.md similarity index 100% rename from content/posts/2013-10-31-deploying-with-git-deploy.md rename to content/posts/2013/2013-10-31-deploying-with-git-deploy.md diff --git a/content/posts/2014-04-03-pretty-difficult-privacy.md b/content/posts/2014/2014-04-03-pretty-difficult-privacy.md similarity index 100% rename from content/posts/2014-04-03-pretty-difficult-privacy.md rename to content/posts/2014/2014-04-03-pretty-difficult-privacy.md diff --git a/content/posts/2014-04-03-to-blog-or-not-to-blog.md b/content/posts/2014/2014-04-03-to-blog-or-not-to-blog.md similarity index 100% rename from content/posts/2014-04-03-to-blog-or-not-to-blog.md rename to content/posts/2014/2014-04-03-to-blog-or-not-to-blog.md diff --git a/content/posts/2014-04-04-dealing-with-technical-debt.md b/content/posts/2014/2014-04-04-dealing-with-technical-debt.md similarity index 100% rename from content/posts/2014-04-04-dealing-with-technical-debt.md rename to content/posts/2014/2014-04-04-dealing-with-technical-debt.md diff --git a/content/posts/2014-04-15-testing-home-with-cucumber-and-aruba.md b/content/posts/2014/2014-04-15-testing-home-with-cucumber-and-aruba.md similarity index 100% rename from content/posts/2014-04-15-testing-home-with-cucumber-and-aruba.md rename to content/posts/2014/2014-04-15-testing-home-with-cucumber-and-aruba.md diff --git a/content/posts/2014-06-04-gpg-sign-your-git-commits.md b/content/posts/2014/2014-06-04-gpg-sign-your-git-commits.md similarity index 100% rename from content/posts/2014-06-04-gpg-sign-your-git-commits.md rename to content/posts/2014/2014-06-04-gpg-sign-your-git-commits.md diff --git a/content/posts/2014-08-29-synchronize-goroutines-in-your-tests.md b/content/posts/2014/2014-08-29-synchronize-goroutines-in-your-tests.md similarity index 100% rename from content/posts/2014-08-29-synchronize-goroutines-in-your-tests.md rename to content/posts/2014/2014-08-29-synchronize-goroutines-in-your-tests.md diff --git a/content/posts/2014-10-15-rails-prevent-accidental-debugging-commits.md b/content/posts/2014/2014-10-15-rails-prevent-accidental-debugging-commits.md similarity index 100% rename from content/posts/2014-10-15-rails-prevent-accidental-debugging-commits.md rename to content/posts/2014/2014-10-15-rails-prevent-accidental-debugging-commits.md diff --git a/content/posts/2014-11-20-why-i-dropped-fish-in-favour-of-zsh.md b/content/posts/2014/2014-11-20-why-i-dropped-fish-in-favour-of-zsh.md similarity index 100% rename from content/posts/2014-11-20-why-i-dropped-fish-in-favour-of-zsh.md rename to content/posts/2014/2014-11-20-why-i-dropped-fish-in-favour-of-zsh.md diff --git a/content/posts/2015-04-07-testing-with-minitest.md b/content/posts/2015/2015-04-07-testing-with-minitest.md similarity index 100% rename from content/posts/2015-04-07-testing-with-minitest.md rename to content/posts/2015/2015-04-07-testing-with-minitest.md diff --git a/content/posts/2015-08-05-postgresql-error-type-hstore-does-not-exist.md b/content/posts/2015/2015-08-05-postgresql-error-type-hstore-does-not-exist.md similarity index 100% rename from content/posts/2015-08-05-postgresql-error-type-hstore-does-not-exist.md rename to content/posts/2015/2015-08-05-postgresql-error-type-hstore-does-not-exist.md diff --git a/content/posts/2015-10-03-a-makefile-for-golang-cli-tools.md b/content/posts/2015/2015-10-03-a-makefile-for-golang-cli-tools.md similarity index 100% rename from content/posts/2015-10-03-a-makefile-for-golang-cli-tools.md rename to content/posts/2015/2015-10-03-a-makefile-for-golang-cli-tools.md diff --git a/content/posts/2015-10-12-building-golang-cli-tools-update.md b/content/posts/2015/2015-10-12-building-golang-cli-tools-update.md similarity index 100% rename from content/posts/2015-10-12-building-golang-cli-tools-update.md rename to content/posts/2015/2015-10-12-building-golang-cli-tools-update.md diff --git a/content/posts/2015-11-27-rails-generate-model-be-specific.md b/content/posts/2015/2015-11-27-rails-generate-model-be-specific.md similarity index 100% rename from content/posts/2015-11-27-rails-generate-model-be-specific.md rename to content/posts/2015/2015-11-27-rails-generate-model-be-specific.md diff --git a/content/posts/2015-12-04-el-capitan-safari-new-tab-slow-fix.md b/content/posts/2015/2015-12-04-el-capitan-safari-new-tab-slow-fix.md similarity index 100% rename from content/posts/2015-12-04-el-capitan-safari-new-tab-slow-fix.md rename to content/posts/2015/2015-12-04-el-capitan-safari-new-tab-slow-fix.md diff --git a/content/posts/2016-01-06-putting-ariejan-net-on-a-diet-a-69-percent-reduction.md b/content/posts/2016/2016-01-06-putting-ariejan-net-on-a-diet-a-69-percent-reduction.md similarity index 100% rename from content/posts/2016-01-06-putting-ariejan-net-on-a-diet-a-69-percent-reduction.md rename to content/posts/2016/2016-01-06-putting-ariejan-net-on-a-diet-a-69-percent-reduction.md diff --git a/content/posts/2016-04-15-hanami-and-multi-database-testing-with-travis.md b/content/posts/2016/2016-04-15-hanami-and-multi-database-testing-with-travis.md similarity index 100% rename from content/posts/2016-04-15-hanami-and-multi-database-testing-with-travis.md rename to content/posts/2016/2016-04-15-hanami-and-multi-database-testing-with-travis.md diff --git a/content/posts/2016-04-24-music-streaming-setup.md b/content/posts/2016/2016-04-24-music-streaming-setup.md similarity index 100% rename from content/posts/2016-04-24-music-streaming-setup.md rename to content/posts/2016/2016-04-24-music-streaming-setup.md diff --git a/content/posts/2016-08-17-squash-git-commits-when-merging.md b/content/posts/2016/2016-08-17-squash-git-commits-when-merging.md similarity index 100% rename from content/posts/2016-08-17-squash-git-commits-when-merging.md rename to content/posts/2016/2016-08-17-squash-git-commits-when-merging.md diff --git a/content/posts/2017-03-08-bitcoin-mining-anno-2017.md b/content/posts/2017/2017-03-08-bitcoin-mining-anno-2017.md similarity index 100% rename from content/posts/2017-03-08-bitcoin-mining-anno-2017.md rename to content/posts/2017/2017-03-08-bitcoin-mining-anno-2017.md diff --git a/content/posts/2017-03-20-image-zoom-with-plain-javascript-and-css.md b/content/posts/2017/2017-03-20-image-zoom-with-plain-javascript-and-css.md similarity index 100% rename from content/posts/2017-03-20-image-zoom-with-plain-javascript-and-css.md rename to content/posts/2017/2017-03-20-image-zoom-with-plain-javascript-and-css.md diff --git a/content/posts/2017-03-22-tmux-vim-copy-paste-on-macos-sierra.md b/content/posts/2017/2017-03-22-tmux-vim-copy-paste-on-macos-sierra.md similarity index 100% rename from content/posts/2017-03-22-tmux-vim-copy-paste-on-macos-sierra.md rename to content/posts/2017/2017-03-22-tmux-vim-copy-paste-on-macos-sierra.md diff --git a/content/posts/2017-12-08-bug-severity-explained.md b/content/posts/2017/2017-12-08-bug-severity-explained.md similarity index 100% rename from content/posts/2017-12-08-bug-severity-explained.md rename to content/posts/2017/2017-12-08-bug-severity-explained.md diff --git a/content/posts/2019-08-28-how-to-background-a-running-process-over-ssh.md b/content/posts/2019/2019-08-28-how-to-background-a-running-process-over-ssh.md similarity index 100% rename from content/posts/2019-08-28-how-to-background-a-running-process-over-ssh.md rename to content/posts/2019/2019-08-28-how-to-background-a-running-process-over-ssh.md diff --git a/content/posts/2020-02-28-building-a-nas.md b/content/posts/2020/2020-02-28-building-a-nas.md similarity index 100% rename from content/posts/2020-02-28-building-a-nas.md rename to content/posts/2020/2020-02-28-building-a-nas.md diff --git a/content/posts/2020-03-09-the-git-submodule-cheat-sheet.md b/content/posts/2020/2020-03-09-the-git-submodule-cheat-sheet.md similarity index 100% rename from content/posts/2020-03-09-the-git-submodule-cheat-sheet.md rename to content/posts/2020/2020-03-09-the-git-submodule-cheat-sheet.md diff --git a/content/posts/2020-03-11-drone-hugo-plugin-that-works.md b/content/posts/2020/2020-03-11-drone-hugo-plugin-that-works.md similarity index 100% rename from content/posts/2020-03-11-drone-hugo-plugin-that-works.md rename to content/posts/2020/2020-03-11-drone-hugo-plugin-that-works.md diff --git a/content/posts/2020-03-17-test-flutter-on-drone-ci.md b/content/posts/2020/2020-03-17-test-flutter-on-drone-ci.md similarity index 100% rename from content/posts/2020-03-17-test-flutter-on-drone-ci.md rename to content/posts/2020/2020-03-17-test-flutter-on-drone-ci.md diff --git a/content/posts/2020-03-29-why-i-will-not-repair-your-amplifier.md b/content/posts/2020/2020-03-29-why-i-will-not-repair-your-amplifier.md similarity index 100% rename from content/posts/2020-03-29-why-i-will-not-repair-your-amplifier.md rename to content/posts/2020/2020-03-29-why-i-will-not-repair-your-amplifier.md diff --git a/content/posts/2020-10-03-repairing-a-xiaomi-roborock-s5-max.md b/content/posts/2020/2020-10-03-repairing-a-xiaomi-roborock-s5-max.md similarity index 100% rename from content/posts/2020-10-03-repairing-a-xiaomi-roborock-s5-max.md rename to content/posts/2020/2020-10-03-repairing-a-xiaomi-roborock-s5-max.md diff --git a/content/posts/2020-11-12-the-big-diy-nas-update.md b/content/posts/2020/2020-11-12-the-big-diy-nas-update.md similarity index 100% rename from content/posts/2020-11-12-the-big-diy-nas-update.md rename to content/posts/2020/2020-11-12-the-big-diy-nas-update.md diff --git a/content/posts/2020-11-18-10gb-ethernet-proxmox-and-ryzentosh-catalina.md b/content/posts/2020/2020-11-18-10gb-ethernet-proxmox-and-ryzentosh-catalina.md similarity index 100% rename from content/posts/2020-11-18-10gb-ethernet-proxmox-and-ryzentosh-catalina.md rename to content/posts/2020/2020-11-18-10gb-ethernet-proxmox-and-ryzentosh-catalina.md diff --git a/content/posts/2023-05-17-base2tone-cave-dark-for-slack.md b/content/posts/2023/2023-05-17-base2tone-cave-dark-for-slack.md similarity index 100% rename from content/posts/2023-05-17-base2tone-cave-dark-for-slack.md rename to content/posts/2023/2023-05-17-base2tone-cave-dark-for-slack.md diff --git a/content/posts/2024-01-24-prepare-new-hard-disk-for-zfs-nas.md b/content/posts/2024/2024-01-24-prepare-new-hard-disk-for-zfs-nas.md similarity index 100% rename from content/posts/2024-01-24-prepare-new-hard-disk-for-zfs-nas.md rename to content/posts/2024/2024-01-24-prepare-new-hard-disk-for-zfs-nas.md diff --git a/content/posts/2024-01-24-volkswagen-golf-cabrio-update.md b/content/posts/2024/2024-01-24-volkswagen-golf-cabrio-update.md similarity index 100% rename from content/posts/2024-01-24-volkswagen-golf-cabrio-update.md rename to content/posts/2024/2024-01-24-volkswagen-golf-cabrio-update.md diff --git a/content/posts/2024-01-27-troubleshooting-zfs-online-not-working.md b/content/posts/2024/2024-01-27-troubleshooting-zfs-online-not-working.md similarity index 100% rename from content/posts/2024-01-27-troubleshooting-zfs-online-not-working.md rename to content/posts/2024/2024-01-27-troubleshooting-zfs-online-not-working.md