<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>david winter</title><link href="https://davidwinter.dev/" rel="alternate"/><link href="https://davidwinter.dev/index.xml" rel="self"/><id>https://davidwinter.dev/</id><updated>2026-07-08T00:00:00+01:00</updated><entry><title>Keeping Claude Code MCP credentials out of git with 1Password</title><link href="https://davidwinter.dev/2026/07/08/1password-claude-code-mcp-credentials/" rel="alternate"/><published>2026-07-08T00:00:00+01:00</published><updated>2026-07-08T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2026-07-08:/2026/07/08/1password-claude-code-mcp-credentials/</id><summary type="html">&lt;p&gt;Resolve MCP server tokens from 1Password at launch so Claude Code gets its credentials without a single secret ever landing in a committed config file.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I commit parts of my &lt;a href="https://claude.com/claude-code"&gt;Claude Code&lt;/a&gt; setup to git so it follows me between machines and stays version controlled. The trouble is that MCP servers often need credentials, an API token here, a bearer token there, and those absolutely cannot go into a file that&amp;rsquo;s tracked in a repo. I already keep everything in &lt;a href="https://1password.com"&gt;1Password&lt;/a&gt; and use its CLI daily, so the answer was to have Claude Code pull the tokens from there at the moment it needs them, rather than store them anywhere on disk.&lt;/p&gt;
&lt;p&gt;The result is a &lt;code&gt;.mcp.json&lt;/code&gt; I&amp;rsquo;m happy to commit. It describes every server, but holds no secrets. Each one that needs a credential resolves it at launch through a helper command that reads from 1Password, so the token only ever exists in memory while the server is running.&lt;/p&gt;
&lt;h2&gt;How the credential gets injected&lt;/h2&gt;
&lt;p&gt;Claude Code supports a &lt;code&gt;headersHelper&lt;/code&gt; field on an HTTP MCP server. Instead of a static header value, you give it a command, and Claude Code runs that command when it starts the server and merges the output into the request headers. The command has to print a single JSON object mapping header names to values.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s the hook. The command reads the secret from 1Password with &lt;code&gt;op read&lt;/code&gt; and the &lt;code&gt;op://vault/item/field&lt;/code&gt; reference format, so the reference (which is safe to commit) lives in the config, and the actual value is fetched on demand.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; you need the 1Password desktop app installed, with CLI integration enabled under &lt;em&gt;Settings &amp;gt; Developer &amp;gt; &amp;ldquo;Integrate with 1Password CLI&amp;rdquo;&lt;/em&gt;. I&amp;rsquo;m frequently between a mixture of WSL, Linux and macOS, but on WSL, the CLI is the Windows binary invoked as &lt;code&gt;op.exe&lt;/code&gt;; on macOS or Linux it&amp;rsquo;s just &lt;code&gt;op&lt;/code&gt;. In future, I&amp;rsquo;ll create an alias within my Fish shell so that &lt;code&gt;op&lt;/code&gt; is available on all platforms!&lt;/p&gt;
&lt;h2&gt;Adding a server the right way&lt;/h2&gt;
&lt;p&gt;The important detail is to add servers with &lt;code&gt;claude mcp add-json&lt;/code&gt;, not the plain &lt;code&gt;claude mcp add&lt;/code&gt;. The plain command&amp;rsquo;s &lt;code&gt;--header&lt;/code&gt; flag only stores static values, which would defeat the whole point. The JSON variant takes a raw blob, so it&amp;rsquo;s the only path that can carry the dynamic &lt;code&gt;headersHelper&lt;/code&gt; field.&lt;/p&gt;
&lt;p&gt;Store the credential in 1Password first, note its &lt;code&gt;op://vault/item/field&lt;/code&gt; reference, then feed the template to &lt;code&gt;add-json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;claude&lt;span class="w"&gt; &lt;/span&gt;mcp&lt;span class="w"&gt; &lt;/span&gt;add-json&lt;span class="w"&gt; &lt;/span&gt;--scope&lt;span class="w"&gt; &lt;/span&gt;project&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;server-name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{&lt;/span&gt;
&lt;span class="s1"&gt;    &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;/span&gt;
&lt;span class="s1"&gt;    &amp;quot;url&amp;quot;: &amp;quot;&amp;lt;mcp-endpoint-url&amp;gt;&amp;quot;,&lt;/span&gt;
&lt;span class="s1"&gt;    &amp;quot;headersHelper&amp;quot;: &amp;quot;printf &amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{\&amp;quot;&amp;lt;Header-Name&amp;gt;\&amp;quot;: \&amp;quot;%s\&amp;quot;}&amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; \&amp;quot;$(op.exe read &amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;op://&amp;lt;Vault&amp;gt;/&amp;lt;Item&amp;gt;/&amp;lt;field&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;)\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s1"&gt;  }&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Remember, change &lt;code&gt;op.exe&lt;/code&gt; to just &lt;code&gt;op&lt;/code&gt; on macOS or Linux. &lt;/p&gt;
&lt;p&gt;Restart Claude Code afterwards and confirm the server connects. The quoting looks fierce, but you&amp;rsquo;re only ever changing the header name, the URL, and the &lt;code&gt;op://&lt;/code&gt; reference.&lt;/p&gt;
&lt;h2&gt;A single secret&lt;/h2&gt;
&lt;p&gt;Most servers need one bearer token in an &lt;code&gt;Authorization&lt;/code&gt; header. Here&amp;rsquo;s GitHub, pinned to read-only tools with the &lt;code&gt;/readonly&lt;/code&gt; on the URL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;claude&lt;span class="w"&gt; &lt;/span&gt;mcp&lt;span class="w"&gt; &lt;/span&gt;add-json&lt;span class="w"&gt; &lt;/span&gt;--scope&lt;span class="w"&gt; &lt;/span&gt;project&lt;span class="w"&gt; &lt;/span&gt;github&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{&lt;/span&gt;
&lt;span class="s1"&gt;    &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;/span&gt;
&lt;span class="s1"&gt;    &amp;quot;url&amp;quot;: &amp;quot;https://api.githubcopilot.com/mcp/readonly&amp;quot;,&lt;/span&gt;
&lt;span class="s1"&gt;    &amp;quot;headersHelper&amp;quot;: &amp;quot;printf &amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{\&amp;quot;Authorization\&amp;quot;: \&amp;quot;Bearer %s\&amp;quot;}&amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; \&amp;quot;$(op.exe read &amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;op://Employee/GitHub token/credential&amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;)\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s1"&gt;  }&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;More than one secret&lt;/h2&gt;
&lt;p&gt;When a server needs two credentials, send them as two headers. Extend the &lt;code&gt;printf&lt;/code&gt; format string with another &lt;code&gt;%s&lt;/code&gt; and add one &lt;code&gt;op.exe read&lt;/code&gt; per placeholder, in order. Datadog wants an API key and an application key:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;claude&lt;span class="w"&gt; &lt;/span&gt;mcp&lt;span class="w"&gt; &lt;/span&gt;add-json&lt;span class="w"&gt; &lt;/span&gt;--scope&lt;span class="w"&gt; &lt;/span&gt;project&lt;span class="w"&gt; &lt;/span&gt;datadog&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{&lt;/span&gt;
&lt;span class="s1"&gt;    &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;/span&gt;
&lt;span class="s1"&gt;    &amp;quot;url&amp;quot;: &amp;quot;https://mcp.datadoghq.eu/api/unstable/mcp-server/mcp&amp;quot;,&lt;/span&gt;
&lt;span class="s1"&gt;    &amp;quot;headersHelper&amp;quot;: &amp;quot;printf &amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{\&amp;quot;DD_API_KEY\&amp;quot;: \&amp;quot;%s\&amp;quot;, \&amp;quot;DD_APPLICATION_KEY\&amp;quot;: \&amp;quot;%s\&amp;quot;}&amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; \&amp;quot;$(op.exe read &amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;op://Employee/Datadog API key token/credential&amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;)\&amp;quot; \&amp;quot;$(op.exe read &amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;op://Employee/Datadog MCP token/credential&amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;)\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s1"&gt;  }&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With this in place my Claude Code config is fully committable. The tokens stay in 1Password, unlocked by the desktop app I&amp;rsquo;ve already authenticated, and they&amp;rsquo;re pulled into memory only when a server starts. Nothing sensitive now ever touches the repo.&lt;/p&gt;</content><category term="claude-code"/><category term="1password"/><category term="cli"/><category term="security"/></entry><entry><title>Making Firefox open new tabs where I expect</title><link href="https://davidwinter.dev/2026/06/22/firefox-new-tab-position/" rel="alternate"/><published>2026-06-22T00:00:00+01:00</published><updated>2026-06-22T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2026-06-22:/2026/06/22/firefox-new-tab-position/</id><summary type="html">&lt;p&gt;Three about:config settings that fix where Firefox drops new tabs, especially when pinned tabs are involved.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I keep a lot of tabs open. Probably too many. I also lean on pinned tabs for the handful of things I always have running, like email and my calendar. The trouble is what happens when I open a new tab: instead of landing at the far right where I go looking for it, it would often appear at the far left, wedged in right after my pinned tabs. With a busy tab strip that&amp;rsquo;s just enough friction to be annoying every single time.&lt;/p&gt;
&lt;p&gt;After some digging in &lt;a href="https://support.mozilla.org/en-US/kb/about-config-editor-firefox"&gt;&lt;code&gt;about:config&lt;/code&gt;&lt;/a&gt;, I&amp;rsquo;ve settled on three settings that get the behaviour I want:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;browser.tabs.insertAfterCurrent              false
browser.tabs.insertAfterCurrentExceptPinned  true
browser.tabs.insertRelatedAfterCurrent       true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To change them, open &lt;code&gt;about:config&lt;/code&gt;, search for each name in turn, and set the value. Two of these are actually Firefox&amp;rsquo;s defaults; the third is the one that fixes my real gripe. It&amp;rsquo;s worth walking through what each one does, because they only make sense together.&lt;/p&gt;
&lt;h2&gt;Opening a blank tab&lt;/h2&gt;
&lt;p&gt;When I open a fresh, empty tab with &lt;code&gt;Cmd+T&lt;/code&gt; or the &lt;code&gt;+&lt;/code&gt; button, I want it at the far right, on the end of the strip. That&amp;rsquo;s &lt;code&gt;browser.tabs.insertAfterCurrent&lt;/code&gt; left at its default of &lt;code&gt;false&lt;/code&gt;. With dozens of tabs open, a new blank tab belongs at the end where there&amp;rsquo;s room, not shoved into the middle next to whatever I happened to be looking at.&lt;/p&gt;
&lt;h2&gt;Opening a link from a normal page&lt;/h2&gt;
&lt;p&gt;When I open a link in a new tab, by middle-clicking or using &lt;em&gt;Open Link in New Tab&lt;/em&gt;, it opens immediately to the right of the tab I opened it from. That&amp;rsquo;s &lt;code&gt;browser.tabs.insertRelatedAfterCurrent&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;, also a default.&lt;/p&gt;
&lt;p&gt;This one I genuinely want. If I&amp;rsquo;m reading an article and open three links from it, they line up right next to that article rather than scattering to the far end. The new tabs are clearly related to where they came from, and when I&amp;rsquo;m done I can close the little cluster without hunting around.&lt;/p&gt;
&lt;h2&gt;Opening a link from a pinned tab&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the setting that does the real work: &lt;code&gt;browser.tabs.insertAfterCurrentExceptPinned&lt;/code&gt;, set to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A pinned tab counts as the current tab, so the &amp;ldquo;related after current&amp;rdquo; rule above would happily drop a new tab right after my pinned tabs, at the far left. That was the exact behaviour driving me up the wall. This setting carves out an exception: when the current tab is pinned, send the new tab to the far right end instead of crowding it in beside the pinned ones.&lt;/p&gt;
&lt;p&gt;The result is that my pinned tabs stay a tidy, fixed cluster on the left, and anything I open from them shows up on the right where I&amp;rsquo;d naturally look. Best of both worlds!&lt;/p&gt;
&lt;h2&gt;The catch: these don&amp;rsquo;t sync&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s one real frustration. I use &lt;a href="https://www.mozilla.org/en-US/firefox/sync/"&gt;Firefox Sync&lt;/a&gt; to keep most of my setup consistent across devices, extensions especially, and it does a great job. But &lt;code&gt;about:config&lt;/code&gt; preferences like these aren&amp;rsquo;t part of what it syncs. Set them up on one machine and you&amp;rsquo;re starting from scratch on the next.&lt;/p&gt;
&lt;p&gt;So every time I set up Firefox somewhere new, I&amp;rsquo;m back to hunting through &lt;code&gt;about:config&lt;/code&gt; from memory. That&amp;rsquo;s exactly the kind of repetitive, easy-to-forget setup my dotfiles repo exists to handle, and I&amp;rsquo;m exploring whether I can manage these preferences from there instead, most likely through a &lt;code&gt;user.js&lt;/code&gt; file dropped into the profile. I&amp;rsquo;ll write that up separately if I land on something that works.&lt;/p&gt;
&lt;p&gt;For now though, my tabs finally open where I expect them to. Small win, daily payoff.&lt;/p&gt;</content><category term="firefox"/></entry><entry><title>RustDesk direct connections over Tailscale</title><link href="https://davidwinter.dev/2026/06/06/rustdesk-via-tailscale/" rel="alternate"/><published>2026-06-06T00:00:00+01:00</published><updated>2026-06-06T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2026-06-06:/2026/06/06/rustdesk-via-tailscale/</id><summary type="html">&lt;p&gt;Skip the public RustDesk server entirely and connect straight to your machines over their Tailscale IP addresses.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I use &lt;a href="https://rustdesk.com"&gt;RustDesk&lt;/a&gt; to help family with their computers from a distance. Out of the box it routes through the public RustDesk server, which is the path of least resistance when you&amp;rsquo;re getting started. But, that changed recently; a &lt;a href="https://github.com/rustdesk/rustdesk/wiki/Login-required-for-public-server"&gt;login is now required for the public server&lt;/a&gt;, and that&amp;rsquo;s because the public server was only ever meant for testing and demonstration apparently, and because of growing botnet and scam abuse.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t want to have to self-host a relay server for the handful of machines I connect to. All of those machines are already on my &lt;a href="https://tailscale.com"&gt;Tailscale&lt;/a&gt; network, so they can already reach each other. That makes the public server redundant. I can point RustDesk straight at a machine&amp;rsquo;s Tailscale IP and skip the middleman!&lt;/p&gt;
&lt;h2&gt;Enabling direct IP access&lt;/h2&gt;
&lt;p&gt;On the machine you want to control, open RustDesk and click the three-dot menu next to its ID, then go to &lt;em&gt;Settings&lt;/em&gt;. Under the &lt;em&gt;Security&lt;/em&gt; section, click to unlock it, and tick &lt;em&gt;Enable direct IP access&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is what lets a RustDesk client connect to this machine by its IP address rather than going via the relay.&lt;/p&gt;
&lt;h2&gt;Setting a permanent password&lt;/h2&gt;
&lt;p&gt;While you&amp;rsquo;re still in the &lt;em&gt;Security&lt;/em&gt; section, scroll up to the &lt;em&gt;Password&lt;/em&gt; area and set a permanent password. Without one, RustDesk generates a temporary password that rotates, which is no good when you want to connect again later without being sat in front of the machine.&lt;/p&gt;
&lt;p&gt;I store the password in &lt;a href="https://1password.com"&gt;1Password&lt;/a&gt; so it&amp;rsquo;s there whenever I need it. &lt;strong&gt;Note:&lt;/strong&gt; treat this like any other credential, since anyone with the password and network access to the machine can connect.&lt;/p&gt;
&lt;h2&gt;Finding the Tailscale IP&lt;/h2&gt;
&lt;p&gt;Each machine on your Tailscale network has its own stable IP in the &lt;code&gt;100.x.x.x&lt;/code&gt; range. You can grab it from the Tailscale client in the menu bar or system tray, or from the &lt;a href="https://login.tailscale.com/admin/machines"&gt;machines list&lt;/a&gt; in the admin console.&lt;/p&gt;
&lt;p&gt;That IP stays the same as long as the device is part of your network, so it&amp;rsquo;s worth noting down alongside the password.&lt;/p&gt;
&lt;h2&gt;Connecting&lt;/h2&gt;
&lt;p&gt;On the machine you&amp;rsquo;re connecting from, paste the Tailscale IP into the &lt;em&gt;Control Remote Desktop&lt;/em&gt; field and connect. Enter the permanent password when prompted, and you&amp;rsquo;re in.&lt;/p&gt;
&lt;p&gt;RustDesk will warn that this is a direct and unencrypted connection. That warning is about RustDesk&amp;rsquo;s own transport, but the traffic is already running inside Tailscale&amp;rsquo;s encrypted tunnel, so it&amp;rsquo;s safe to proceed.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s the whole setup. As long as both machines are on Tailscale, I connect directly, with no shared server and no login in the way! Problem solved.&lt;/p&gt;</content><category term="tailscale"/><category term="rustdesk"/></entry><entry><title>Post-deployment triggers for PaaS providers</title><link href="https://davidwinter.dev/2023/03/14/post-deploy-triggers/" rel="alternate"/><published>2023-03-14T00:00:00+00:00</published><updated>2023-03-14T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2023-03-14:/2023/03/14/post-deploy-triggers/</id><summary type="html">&lt;p&gt;Not all hosting providers offer a mechanism to trigger follow up actions after a deployment. Here are a few examples using GitHub Actions to achieve it.&lt;/p&gt;</summary><content type="html">&lt;p&gt;For really simple projects, PaaS providers such as &lt;a href="https://fly.io"&gt;Fly.io&lt;/a&gt; and &lt;a href="https://render.com"&gt;render.com&lt;/a&gt; offer a pain-free way to get an app or static site up and running in minutes. Sometimes you may want to trigger some follow up actions after a deployment, for example, a Slack notification to notify your team that a new release is live, or some smoke tests.&lt;/p&gt;
&lt;p&gt;The above two providers are quite different in how they handle deployments. Fly.io lets you run a command to deploy from your local machine. With render.com, it integrates with your Git provider and monitors pushes to the repository, and then initiates a deployment itself.&lt;/p&gt;
&lt;p&gt;But with either mechanism, you want to have confidence when your change has been successfully deployed.&lt;/p&gt;
&lt;p&gt;A number of factors might cause a delay before the change is publically visible. For example, caching by the hosting provider, or even your own caching layer, might mean that if they flag it is having been deployed, it might take a further few seconds or minutes before that is reflected across their CDN (something I&amp;rsquo;ve certainly noticed with render.com).&lt;/p&gt;
&lt;p&gt;The examples below will offer some more concrete certainty based on Git commit hashes. Exposing and then testing your site against an expected Git hash being available is the key to this method.&lt;/p&gt;
&lt;h2&gt;Exposing the Git hash - static vs dynamic sites&lt;/h2&gt;
&lt;p&gt;A simple example for a dynamic site is to offer a version check endpoint at a known URL route. Here you allow your deployment pipeline to pass in a commit hash based on the commit that is being deployed, and the app will check this against it&amp;rsquo;s known deployed commit hash and return either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;404&lt;/code&gt; status indicating that version is not yet deployed (not found)&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;204&lt;/code&gt; success status, yet we don&amp;rsquo;t need to provide any content in the response&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;render.com offers an environment variable &lt;code&gt;RENDER_GIT_COMMIT&lt;/code&gt; for the running application, and so &lt;a href="https://github.com/davidwinter/render-post-deploy"&gt;an example&lt;/a&gt; looks like this for a &lt;a href="https://github.com/davidwinter/render-post-deploy/blob/main/app.rb"&gt;Ruby based Sinatra app&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/version-check/:commit&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:commit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;RENDER_GIT_COMMIT&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For a static site that is built with a tool such as Hugo, then you need to approach this a slightly different way. When the site is built, generate a static file named with the Git commit hash. We will then be able to check if the file exists, which will return either a &lt;code&gt;404&lt;/code&gt;, or &lt;code&gt;200&lt;/code&gt; by the web server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;static/version-check
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;static/version-check/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GITHUB_SHA&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With Hugo, files within the &lt;code&gt;static&lt;/code&gt; directory are served as they are, unmanipulated, at the root of the project.&lt;/p&gt;
&lt;p&gt;Both static and dynamic projects will use the URL format of:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/version-check/COMMIT_HASH
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/version-check/df5222b2ac95769803a54cc44ef9698aff65be34
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Testing for the presence of the correct commit&lt;/h2&gt;
&lt;p&gt;Once the PaaS solution has begun, or indicated the deployment is complete, you need to check for the presence of the latest commit hash. With GitHub Actions, you can use &lt;code&gt;${GITHUB_SHA}&lt;/code&gt; to determine this.&lt;/p&gt;
&lt;p&gt;You can use the Node.js tool &lt;code&gt;wait-on&lt;/code&gt; or &lt;code&gt;curl&lt;/code&gt; to retry the URL until it receives a &lt;code&gt;2xx&lt;/code&gt; (successful) status. The &lt;code&gt;curl&lt;/code&gt; option might be more appropriate if you don&amp;rsquo;t have or want to setup Node.js within your deployment pipeline.&lt;/p&gt;
&lt;p&gt;For &lt;code&gt;wait-on&lt;/code&gt;, you can use this in your pipeline run steps:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;npx&lt;span class="w"&gt; &lt;/span&gt;wait-on&lt;span class="w"&gt; &lt;/span&gt;--timeout&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;600000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://yourapp.com/version-check/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GITHUB_SHA&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will wait 600,000 miliseconds, or 10 minutes, before exiting in failure.&lt;/p&gt;
&lt;p&gt;And for &lt;code&gt;curl&lt;/code&gt;, you can use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--head&lt;span class="w"&gt; &lt;/span&gt;--retry&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--retry-all-errors&lt;span class="w"&gt; &lt;/span&gt;--fail&lt;span class="w"&gt; &lt;/span&gt;--retry-delay&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://yourapp.com/version-check/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GITHUB_SHA&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After these commands have run successfully, then you&amp;rsquo;re free to run any subsequent commands that you want to trigger.&lt;/p&gt;
&lt;h2&gt;GitHub Actions full examples&lt;/h2&gt;
&lt;p&gt;For my blog, I use something similar to the below for a Hugo build handled on Fly.io:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;deploy&lt;/span&gt;

&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;main&lt;/span&gt;

&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;ubuntu-latest&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;actions/checkout@v3&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;# Hugo uses submodules for themes:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;submodules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;recursive&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;# I use `enableGitInfo` for Hugo:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;fetch-depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;0&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;create version check file&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="no"&gt;mkdir -p static/version-check \&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="no"&gt;&amp;amp;&amp;amp; echo &amp;quot;ok&amp;quot; &amp;gt; &amp;quot;static/version-check/${GITHUB_SHA}&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;superfly/flyctl-actions/setup-flyctl@master&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;deploy to fly&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;flyctl deploy --remote-only&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;FLY_API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;${{ secrets.FLY_API_TOKEN }}&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;actions/setup-node@v3&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;node-version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;18&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;wait for deployment to be active&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;npx wait-on --timeout 600000 &amp;quot;https://davidwinter.dev/version-check/${GITHUB_SHA}&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;deploy_wait&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;continue-on-error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;true&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;send Telegram success message&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;if&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;steps.deploy_wait.outcome == &amp;#39;success&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;appleboy/telegram-action@v0.1.1&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;${{ secrets.TELEGRAM_CHAT_ID }}&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;${{ secrets.TELEGRAM_BOT_TOKEN }}&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;markdown&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="no"&gt;🎉 davidwinter.dev deployed!&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="no"&gt;Git SHA: `${{ github.sha }}`&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="no"&gt;https://davidwinter.dev&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;send Telegram fail message&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;if&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;steps.deploy_wait.outcome != &amp;#39;success&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;appleboy/telegram-action@v0.1.1&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;${{ secrets.TELEGRAM_CHAT_ID }}&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;${{ secrets.TELEGRAM_BOT_TOKEN }}&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;markdown&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="no"&gt;🚨 davidwinter.dev failed to deploy&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="no"&gt;Git SHA: `${{ github.sha }}`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And for a dynamic site deployed to render.com, you can see a small example application written in Ruby with Sinatra here: &lt;a href="https://github.com/davidwinter/render-post-deploy"&gt;https://github.com/davidwinter/render-post-deploy&lt;/a&gt;&lt;/p&gt;</content><category term="cicd"/></entry><entry><title>Simple Electron automatic updates</title><link href="https://davidwinter.dev/2020/10/31/electron-auto-update/" rel="alternate"/><published>2020-10-31T00:00:00+00:00</published><updated>2020-10-31T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2020-10-31:/2020/10/31/electron-auto-update/</id><summary type="html">&lt;p&gt;If you&amp;rsquo;re using &lt;code&gt;electron-builder&lt;/code&gt; to publish your applications, then electron-auto-update provides you with a user-friendly simple auto update mechanism with one method call.&lt;/p&gt;</summary><content type="html">&lt;p&gt;For my note-taking application, &lt;strong&gt;&lt;a href="https://nimblenote.app"&gt;nimblenote&lt;/a&gt;&lt;/strong&gt;, I was looking for the simplest way to handle automatic updates for the user. I was keen to be in a position whereby when I publish new versions of the app that its users were onboarded to that new version as quickly as possible. Ensuring people aren&amp;rsquo;t stuck on old versions of your app is essential, especially when it comes to fixing any bugs, and dealing with support issues.&lt;/p&gt;
&lt;p&gt;I use the amazing &lt;a href="https://www.electron.build/"&gt;&lt;code&gt;electron-builder&lt;/code&gt;&lt;/a&gt; package, which handles the packaging and publishing of &lt;a href="https://nimblenote.app"&gt;nimblenote&lt;/a&gt;. It offers a simple auto-update mechanism via &lt;code&gt;electron-updater&lt;/code&gt;, however, it uses your operating-system based notifications which are often missed when they appear, or sometimes snoozed or disabled entirely.&lt;/p&gt;
&lt;p&gt;Operating system notifications weren&amp;rsquo;t going to cut it for me. I wanted to be able to present a dialog box which would allow the user to easily relaunch and update the application with one button click. Although &lt;code&gt;electron-updater&lt;/code&gt; does offer all you need to do this via an extendable API, it was going to result in around 100 lines of code to achieve what I wanted&amp;mdash;and also&amp;mdash;that wasn&amp;rsquo;t going to be easy to reuse, unless&amp;hellip; I packaged up the functionality into a package!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Introducing &lt;strong&gt;&lt;a href="https://github.com/davidwinter/electron-auto-update"&gt;&lt;code&gt;electron-auto-update&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, which I&amp;rsquo;m very pleased has had almost &lt;strong&gt;1,000 downloads&lt;/strong&gt; in its first week!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This package works in tandem with &lt;code&gt;electron-builder&lt;/code&gt;, which I highly recommend for packaging and publishing your application.&lt;/p&gt;
&lt;p&gt;Install via either &lt;code&gt;yarn add electron-auto-update&lt;/code&gt; or &lt;code&gt;npm add electron-auto-update&lt;/code&gt; and then use in your application with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;autoUpdate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;electron-auto-update&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;autoUpdate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will automatically check for updates every hour, and if available, present a simple dialog:&lt;/p&gt;
&lt;p&gt;&lt;img alt="electron-auto-update screenshot" src="https://raw.githubusercontent.com/davidwinter/electron-auto-update/main/screenshot.png"&gt;&lt;/p&gt;
&lt;p&gt;The user can choose to be reminded later, or opt-out of any subsequent reminders if they choose. The check frequency for updates can also be configured, along with also passing through a &lt;code&gt;logger&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;Head on over to the project on GitHub for the full &lt;a href="https://github.com/davidwinter/electron-auto-update#readme"&gt;&lt;code&gt;README&lt;/code&gt;&lt;/a&gt;, and if you find &lt;code&gt;electron-auto-update&lt;/code&gt; useful in your projects, please consider &lt;a href="https://github.com/sponsors/davidwinter"&gt;sponsoring me on GitHub ♥&lt;/a&gt;.&lt;/p&gt;</content><category term="electron"/></entry><entry><title>Managing GPG with Keybase</title><link href="https://davidwinter.dev/2019/04/25/managing-gpg-with-keybase/" rel="alternate"/><published>2019-04-25T00:00:00+01:00</published><updated>2019-04-25T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2019-04-25:/2019/04/25/managing-gpg-with-keybase/</id><summary type="html">&lt;p&gt;Use Keybase to setup and manage GPG, and start signing your git commits&lt;/p&gt;</summary><content type="html">&lt;p&gt;GPG is a tool used for encryption. Similar to SSH, you have a GPG public and private key. Your private key you keep to yourself, and it is used to encrypt and decrypt messages based on a public key that you share with others.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve always found it quite confusing to manage and setup, and to keep keys in sync amongst computers, however, with some more recent need to use it, I hope that I now have something I can use day-to-day without issue.&lt;/p&gt;
&lt;p&gt;Keybase is a tool that has been around for a number of years now. Originally it had GPG at it&amp;rsquo;s heart, but has since moved to it&amp;rsquo;s own encryption protocol which aims to make encryption easier to use. However, it still supports GPG under the hood too.&lt;/p&gt;
&lt;p&gt;At the end of this blog post, I&amp;rsquo;ll show you how you can sign your Git commits using GPG to add an extra layer of security for other users to ensure your work is from you. And in a later blog post, I&amp;rsquo;ll discuss how to use &lt;code&gt;pass&lt;/code&gt; in a software project for managing and sharing secrets between your team.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll want to make sure you have GPG and Keybase installed before proceeding.&lt;/p&gt;
&lt;h2&gt;Setting up Keybase and GPG&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m using a Mac to do this, and most of these instructions should still work.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll want to visit https://keybase.io/download and download the Keybase application for the platform you&amp;rsquo;re using. Once installed run the application and sign up. This should also add the &lt;code&gt;keybase&lt;/code&gt; command line program too.&lt;/p&gt;
&lt;p&gt;Run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;keybase login
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once you&amp;rsquo;re all logged in, and your first device has been added to your account, you&amp;rsquo;ll want to create your first GPG key. Out of the box, Keybase protocol for encryption, but it does support GPG too. And seeing as this is what we want to use for Github commit signing, and &lt;code&gt;pass&lt;/code&gt; down the line too, we&amp;rsquo;ll go this route.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;keybase pgp gen --multi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Follow the prompts and enter the answers to the various questions that you&amp;rsquo;re asked. When it gives the option of storing your private GPG key on Keybase, I opted for yes, as it makes using it on other devices and computers easier.&lt;/p&gt;
&lt;p&gt;Great, you now have a GPG key!&lt;/p&gt;
&lt;h2&gt;Publishing your key outside of Keybase&lt;/h2&gt;
&lt;p&gt;While Keybase is a great solution, and it stores your public key for other users to find too, not everyone uses Keybase. GPG can be used outside of Keybase using the &lt;code&gt;gpg&lt;/code&gt; tools. To make your key available to those users, you&amp;rsquo;ll want to publish your public key to some of the more popular GPG key servers. This way, other users can pull down your key and use it to verify and decrypt things from yourself.&lt;/p&gt;
&lt;p&gt;Each GPG key you have is represented by a fingerprint. This is a 40 character hexadecimal string. To retrieve this, you can type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gpg -K
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll see some output like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;rsa4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2019&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;04&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;expires: 2035-04-13&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;AB5D447C087FB4DD80E3FA40194134D61D5C337&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Copy your own long fingerprint and use that in the following commands:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;gpg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;keys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;AB5D447C087FB4DD80E3FA40194134D61D5C337&lt;/span&gt;
&lt;span class="nv"&gt;gpg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;keyserver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pgp&lt;/span&gt;.&lt;span class="nv"&gt;mit&lt;/span&gt;.&lt;span class="nv"&gt;edu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;keys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;AB5D447C087FB4DD80E3FA40194134D61D5C337&lt;/span&gt;
&lt;span class="nv"&gt;gpg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;keyserver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;keyserver&lt;/span&gt;.&lt;span class="nv"&gt;ubuntu&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;keys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;AB5D447C087FB4DD80E3FA40194134D61D5C337&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Along with the standard GPG keyserver, this will also upload it to the MIT and Ubuntu servers that are commonly used too.&lt;/p&gt;
&lt;p&gt;Other users would then be able to retrieve your key by using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gpg --recv-keys 3AB5D447C087FB4DD80E3FA40194134D61D5C337
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Using your key on your other machines&lt;/h2&gt;
&lt;p&gt;If you have multiple computers, you&amp;rsquo;ll want to setup the key on other machines too. As you&amp;rsquo;re storing both your public and private key on Keybase, you can easily do this.&lt;/p&gt;
&lt;p&gt;After you&amp;rsquo;ve installed Keybase and GPG on your additional machines, you can run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;keybase&lt;/span&gt; &lt;span class="n"&gt;pgp&lt;/span&gt; &lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;AB5D447C087FB4DD80E3FA40194134D61D5C337&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;gpg&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;
&lt;span class="nn"&gt;keybase&lt;/span&gt; &lt;span class="n"&gt;pgp&lt;/span&gt; &lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;AB5D447C087FB4DD80E3FA40194134D61D5C337&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;gpg&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Signing your Git commits&lt;/h2&gt;
&lt;p&gt;Signing your Git commits is basically adding your own signature to each commit to let others know they have definitely come from you. This is quite important as anyone can configure Git to use your email address, but not everyone has your GPG private key.&lt;/p&gt;
&lt;p&gt;If you visit your Github settings, then on the left hand side select &lt;strong&gt;SSH and GPG Keys&lt;/strong&gt;, then click on &lt;strong&gt;New GPG key&lt;/strong&gt;. You&amp;rsquo;ll want to paste in the public part of your GPG key. You can retrieve this by typing:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;keybase&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pgp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;export&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once you&amp;rsquo;ve clicked on &lt;strong&gt;Add GPG key&lt;/strong&gt; Github will be able to verify commits from you. Now you need to tell Git on your computer to use this key to sign commits.&lt;/p&gt;
&lt;p&gt;Open up your Git config located at &lt;code&gt;~/.gitconfig&lt;/code&gt; and under the &lt;code&gt;[user]&lt;/code&gt; section, you&amp;rsquo;ll want to add:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;signingkey = 3AB5D447C087FB4DD80E3FA40194134D61D5C337
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So it should look like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[user]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;David Winter&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;i@djw.me&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;signingkey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;3AB5D447C087FB4DD80E3FA40194134D61D5C337&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This tells Git which key to use. To enable signing, add the following also:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[commit]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;gpgsign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All of your commits from now on will be signed by your GPG key.&lt;/p&gt;</content></entry><entry><title>Working remotely with SSH and VNC</title><link href="https://davidwinter.dev/2019/03/15/working-remotely-with-ssh-and-vnc/" rel="alternate"/><published>2019-03-15T00:00:00+00:00</published><updated>2019-03-15T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2019-03-15:/2019/03/15/working-remotely-with-ssh-and-vnc/</id><summary type="html">&lt;p&gt;A week long trip out in Spain with the need for CPU power back home&lt;/p&gt;</summary><content type="html">&lt;p&gt;Visiting the house out in Spain is one of our favourite things to do in the off-peak seasons. When it&amp;rsquo;s grey, gloomy and wet back home in the UK, a weeks visit is all you need to top up on Vitamin D and 20-degree heat.&lt;/p&gt;
&lt;p&gt;With a solid 4G connection hooked up the house, remote work is a possibility for me as I just need that connection for web development. My better half needs to do data modelling and has just bought a 16 core PC back home that he uses as a mini-supercomputer. His MacBook out in Spain wouldn&amp;rsquo;t get him far, so I set about setting him up so that he could utilise the processing power back home while sitting by the pool out in Spain.&lt;/p&gt;
&lt;h2&gt;Accessing home IP address&lt;/h2&gt;
&lt;p&gt;With time of the essence before our departure to the airport, I needed a quick and easy way to gain access to our home IP address as it&amp;rsquo;s not a static one and could change at any point. The PC at home would be on all of the time, so I created a small shell script that would run hourly and output the IP address into a Dropbox folder so that it would be retrievable from Spain.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;nano&lt;span class="w"&gt; &lt;/span&gt;/etc/cron.hourly/home_ip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;

dig&lt;span class="w"&gt; &lt;/span&gt;+short&lt;span class="w"&gt; &lt;/span&gt;-4&lt;span class="w"&gt; &lt;/span&gt;myip.opendns.com&lt;span class="w"&gt; &lt;/span&gt;@resolver1.opendns.com&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;~/Dropbox/home_ip.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;+x&lt;span class="w"&gt; &lt;/span&gt;/etc/cron.hourly/home_ip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This would now run daily and Dropbox would keep this in sync for me.&lt;/p&gt;
&lt;h2&gt;SSH&lt;/h2&gt;
&lt;p&gt;Simple enough on Ubuntu:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;openssh-server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Copy over your SSH key from the computer that you&amp;rsquo;ll be connecting to your home PC with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;username&amp;gt;@&amp;lt;local-ip-address-of-home-pc&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It will prompt you for your password, but once the command has completed, you will be able to SSH in without a password.&lt;/p&gt;
&lt;p&gt;If the command tells you that you don&amp;rsquo;t have an SSH key, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh-keygen&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;rsa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can hit enter to accept all of the defaults, but you may want to assign a passphrase to your key for extra security.&lt;/p&gt;
&lt;h2&gt;Port forwarding&lt;/h2&gt;
&lt;p&gt;This can be different depending on your home router, but it&amp;rsquo;s essential to forward a public port on your router onto the SSH service running on your home PC. For us, we decided on a non-standard SSH port. For example, port &lt;code&gt;2200&lt;/code&gt; would forward onto port &lt;code&gt;22&lt;/code&gt; of our home PC.&lt;/p&gt;
&lt;p&gt;In your router settings, also try and fix the DHCP assigned IP address of your home PC, or set it to static if there is an option just to eliminate the risk that the IP address may change on your local network, which would then break the port forwarding.&lt;/p&gt;
&lt;h2&gt;Testing SSH connection&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s a good time to now test the SSH connection outside of your local home network. You can tether to your phone, or visit somewhere else with a different connection.&lt;/p&gt;
&lt;p&gt;You can try the connection with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;george@&lt;span class="k"&gt;$(&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;~/Dropbox/home_ip.txt&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Remember to substitute the port for the one you selected in your router settings and your username. The &lt;code&gt;$(cat ~/Dropbox/home_ip.txt)&lt;/code&gt; will be swapped out for the contents of the file that contains your home IP address.&lt;/p&gt;
&lt;p&gt;You should then have a successful connection via ssh.&lt;/p&gt;
&lt;h2&gt;VNC for remote desktop&lt;/h2&gt;
&lt;p&gt;This is an optional step, but if you want to have a remote desktop experience too, you can enable VNC. In Ubuntu, under sharing preferences, you&amp;rsquo;ll be able to enable this. It&amp;rsquo;s important to set a password to allow for a connection that doesn&amp;rsquo;t require a person at the computer to manually approve the connection. This would not be helpful while out in Spain!&lt;/p&gt;
&lt;p&gt;By default, the Ubuntu VNC server, Vino, has encryption enabled. That&amp;rsquo;s great! However, the built-in macOS VNC client does not support this, so we need to disable it on Ubuntu with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gsettings&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;org.gnome.Vino&lt;span class="w"&gt; &lt;/span&gt;require-encryption&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now on your local network, you can test the connection. From the Finder menu, select &lt;em&gt;Go&lt;/em&gt; &amp;gt; &lt;em&gt;Connect to Server&lt;/em&gt; or push &lt;code&gt;cmd&lt;/code&gt; + &lt;code&gt;k&lt;/code&gt; to open the dialog, then you can enter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;vnc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//&amp;lt;your-local-ip-address&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll be prompted to enter your passphrase and then you can connect and should be able to see the screen share.&lt;/p&gt;
&lt;p&gt;If you trust your local network users, not having encryption enabled is probably fine. However, I would not recommend now opening the VNC port and use port forwarding to gain access to this remotely as it would not be encrypted over the wider internet.&lt;/p&gt;
&lt;p&gt;Instead, let&amp;rsquo;s use SSH tunnelling so that we gain encryption again while also being compatible with the macOS VNC client.&lt;/p&gt;
&lt;h2&gt;SSH tunnel for VNC&lt;/h2&gt;
&lt;p&gt;We already have our SSH port forwarding on our router, so remotely, we just want to set up an SSH tunnel for the local VNC port.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh&lt;span class="w"&gt; &lt;/span&gt;-N&lt;span class="w"&gt; &lt;/span&gt;-L&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5200&lt;/span&gt;:localhost:5200&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;george@&lt;span class="k"&gt;$(&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;~/Dropbox/home_ip.txt&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The important parts of this command are &lt;code&gt;5200:localhost:5200&lt;/code&gt; which tells your computer to tunnel your &lt;code&gt;5200&lt;/code&gt; port with the port &lt;code&gt;5200&lt;/code&gt; on your &lt;code&gt;localhost&lt;/code&gt; machine (in this case the home PC). Everything after this is just the standard SSH connection to the home PC.&lt;/p&gt;
&lt;p&gt;So now, you can connect to your home PC from your Mac with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;vnc://localhost
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And this will be tunnelling to your home PC via the SSH connection, with encryption out of the box.&lt;/p&gt;</content></entry><entry><title>Tmux - the essentials</title><link href="https://davidwinter.dev/2019/03/14/tmux-the-essentials/" rel="alternate"/><published>2019-03-14T00:00:00+00:00</published><updated>2019-03-14T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2019-03-14:/2019/03/14/tmux-the-essentials/</id><summary type="html">&lt;p&gt;With only a handful of commands, tmux can still be your new best friend on the terminal&lt;/p&gt;</summary><content type="html">&lt;p&gt;Tmux is a great tool for managing multiple terminal sessions and layouts. You can disconnect from a tmux session and then reconnect to it later and carry on where you left off. There is a vast amount you can configure with tmux, and many commands that can be used, and at first it can be intimidating to learn and some may fear a steep learning curve. But knowing only a handful of essential commands is enough to be productive day-to-day. I&amp;rsquo;ve been using tmux for the past two years or so and haven&amp;rsquo;t really ventured beyond these, and still, have found plenty of value out of it.&lt;/p&gt;
&lt;h2&gt;Sessions&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve never run tmux before and have no open sessions, just type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tmux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will open a new window with a single pane filling the entire screen.&lt;/p&gt;
&lt;p&gt;One of the features of tmux is the ability to detach from a running tmux session and then be able to reconnect to it at a later time with everything being as you&amp;rsquo;d left it.&lt;/p&gt;
&lt;p&gt;To detach from the new session you&amp;rsquo;ve just created type &lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;b&lt;/code&gt; and then &lt;code&gt;d&lt;/code&gt;. You will now have been returned to your original command prompt.&lt;/p&gt;
&lt;p&gt;You can see the tmux session that you were just connected to by running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tmux&lt;span class="w"&gt; &lt;/span&gt;ls
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To reattach to it, type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tmux&lt;span class="w"&gt; &lt;/span&gt;a
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Tmux prefix command&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s talk about the tmux prefix command; &lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;b&lt;/code&gt;. All commands you run within a tmux session are initiated with this. You press this combination first, and then after, the command you want to run. From here on, we&amp;rsquo;ll reference the prefix with &lt;code&gt;prefix&lt;/code&gt; rather than the full &lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Windows and panes&lt;/h2&gt;
&lt;p&gt;When within tmux there are two basic concepts that you need to know about if you&amp;rsquo;re going to use it productively; windows and panes. You can think of windows as tabs within a tmux session. They are listed along the bottom of the tmux window. Each window can have multiple panes, which are different terminal prompts split across the window in various layouts.&lt;/p&gt;
&lt;h3&gt;Windows&lt;/h3&gt;
&lt;p&gt;Each window is prefixed with a number to represent it. Type &lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;b&lt;/code&gt; and then &lt;code&gt;c&lt;/code&gt; to create a new window. You&amp;rsquo;ll see it appear in the window list and it has been selected. You now have two windows, one represented by &lt;code&gt;0&lt;/code&gt; and the other by &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can switch between windows by typing &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;0&lt;/code&gt; to jump to the first window. Just use the number index to choose which window you want to switch to.&lt;/p&gt;
&lt;p&gt;When you start creating lots of windows, it becomes hard to remember what is within each. By default each window will be named with the default shell it is running. To rename, type &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;,&lt;/code&gt; and then enter a new name, then hit enter. You&amp;rsquo;ll see the name reflected in the window list displayed along the bottom of the screen.&lt;/p&gt;
&lt;h3&gt;Panes&lt;/h3&gt;
&lt;p&gt;Within window 0, let&amp;rsquo;s create some panes. Type &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;%&lt;/code&gt; to split the current window into two vertical panes. You&amp;rsquo;ll notice the right-hand pane currently has the terminal focus.&lt;/p&gt;
&lt;p&gt;Type &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;q&lt;/code&gt; and the number for each pane will briefly appear on the screen. This is how you will navigate between panes. The numbers will disappear after a second or so. Just push the combination again &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;q&lt;/code&gt; and then type &lt;code&gt;0&lt;/code&gt; immediately to switch focus back to the leftmost pane.&lt;/p&gt;
&lt;p&gt;Now go back to the rightmost pane with &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;q&lt;/code&gt; and then &lt;code&gt;1&lt;/code&gt;. We can split this pane in two horizontally by pressing &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;"&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Press &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;q&lt;/code&gt; again and you can now see we have three panes indexed with 0—2.&lt;/p&gt;
&lt;p&gt;Sometimes it&amp;rsquo;s very helpful to &lt;em&gt;zoom in&lt;/em&gt; on a single pane. A good example is when you want to copy and paste the contents of a pane that go over more than one line. To zoom press &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;z&lt;/code&gt;. You&amp;rsquo;ll notice the pane expands to fill the entire window. Also a &lt;code&gt;Z&lt;/code&gt; will appear in the window list along the bottom. To unzoom, just press &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;z&lt;/code&gt; again.&lt;/p&gt;
&lt;h2&gt;Summary of commands&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tmux&lt;/code&gt; create a new tmux session&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tmux ls&lt;/code&gt; list any existing tmux sessions&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tmux a&lt;/code&gt; reattach to the last open tmux session&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;b&lt;/code&gt; the default tmux command prefix&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;d&lt;/code&gt; detach from current tmux session&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;c&lt;/code&gt; create a new window&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;0&lt;/code&gt;-&lt;code&gt;9&lt;/code&gt; to switch to the numbered window&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;,&lt;/code&gt; rename the existing window&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;%&lt;/code&gt; split the current pane into two vertical panes, left and right&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;"&lt;/code&gt; split the current pane into two horizontal panes, top and bottom&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;q&lt;/code&gt; view numbered panes for current window&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;q&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;-&lt;code&gt;9&lt;/code&gt; switch to pane immediately after displaying pane numbers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;z&lt;/code&gt; to zoom and unzoom&lt;/li&gt;
&lt;/ul&gt;</content></entry><entry><title>Quick and simple Github Gist oEmbed support</title><link href="https://davidwinter.dev/2014/10/13/quick-and-simple-github-gist-oembed-support/" rel="alternate"/><published>2014-10-13T00:00:00+01:00</published><updated>2014-10-13T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2014-10-13:/2014/10/13/quick-and-simple-github-gist-oembed-support/</id><summary type="html">&lt;p&gt;Get those code snippets embedded easily&lt;/p&gt;</summary><content type="html">&lt;p&gt;WordPress doesn&amp;rsquo;t come with Github Gist oEmbed support out of the box, which is a shame because sometimes there is nothing quicker than creating a Gist to put in a new tech post by just pasting in the URL.&lt;/p&gt;
&lt;p&gt;Well, it is quite simple to drop in with a WordPress hook that I&amp;rsquo;ve written:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="nx"&gt;wp_embed_register_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;github-gist&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;/^https:\/\/gist\.github\.com\/([^\/]+)\/([^\/]+)/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$matches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rawattr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$embed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;amp;lt;script src=&amp;quot;&lt;/span&gt;&lt;span class="nx"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.js&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;;&lt;/span&gt;

&lt;span class="s2"&gt;        return apply_filters(&lt;/span&gt;
&lt;span class="s2"&gt;            &amp;#39;embed_github_gist&amp;#39;,&lt;/span&gt;
&lt;span class="s2"&gt;            &lt;/span&gt;&lt;span class="si"&gt;$embed&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;
&lt;span class="s2"&gt;            &lt;/span&gt;&lt;span class="si"&gt;$matches&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;
&lt;span class="s2"&gt;            &lt;/span&gt;&lt;span class="si"&gt;$attr&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;
&lt;span class="s2"&gt;            &lt;/span&gt;&lt;span class="si"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;
&lt;span class="s2"&gt;            &lt;/span&gt;&lt;span class="si"&gt;$rawattr&lt;/span&gt;
&lt;span class="s2"&gt;        );&lt;/span&gt;
&lt;span class="s2"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add that code to your themes &lt;code&gt;functions.php&lt;/code&gt; file and then when you&amp;rsquo;re using the visual editor, if you paste in any Github Gist URL, it&amp;rsquo;ll automatically be converted.&lt;/p&gt;</content></entry><entry><title>Install and manage WordPress with Composer</title><link href="https://davidwinter.dev/2014/10/12/install-and-manage-wordpress-with-composer/" rel="alternate"/><published>2014-10-12T00:00:00+01:00</published><updated>2014-10-12T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2014-10-12:/2014/10/12/install-and-manage-wordpress-with-composer/</id><summary type="html">&lt;p&gt;Automated and repeatable WordPress deploys with Composer&lt;/p&gt;</summary><content type="html">&lt;p&gt;Well over two years have passed since my previous blog post on managing &lt;a href="https://davidwinter.me/install-and-manage-wordpress-with-git/"&gt;WordPress with git&lt;/a&gt; was written. A lot has changed since then. &lt;a href="https://getcomposer.org/"&gt;Composer&lt;/a&gt; has taken the PHP world by storm and the majority of developers are seeing the benefits and embracing it.&lt;/p&gt;
&lt;p&gt;Using Composer, you can list a set of requirements for your project, and let it figure out where everything needs to be installed to, what dependencies are required, and how to obtain them.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not familiar with Composer, I would recommend that you go and read the &lt;a href="https://getcomposer.org/doc/00-intro.md"&gt;Getting Started&lt;/a&gt; guide. This howto assumes you have knowledge of, and have perhaps used Composer before. This howto will cover installing WordPress with Composer. Following blog posts will cover installing themes and plugins.&lt;/p&gt;
&lt;h2&gt;Installing WordPress&lt;/h2&gt;
&lt;p&gt;First, you need to make sure you have Composer installed for your project, this is easily done by running the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir my-wordpress-project
cd my-wordpress-project
curl -sS https://getcomposer.org/installer | php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You will now have a &lt;code&gt;composer.phar&lt;/code&gt; file in your project directory.&lt;/p&gt;
&lt;p&gt;Create a new &lt;code&gt;composer.json&lt;/code&gt; file with the following contents:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;repositories&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;package&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;package&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wordpress&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;webroot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;4.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;dist&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;zip&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://github.com/WordPress/WordPress/archive/4.0.zip&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;require&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fancyguy/webroot-installer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;require&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wordpress&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;4.*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fancyguy/webroot-installer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;extra&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;webroot-dir&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;public/wp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;webroot-package&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wordpress&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A quick explanation of what the above is doing for us. WordPress doesn&amp;rsquo;t support Composer installs out of the box - it doesn&amp;rsquo;t provide a &lt;code&gt;composer.json&lt;/code&gt; file. So we have to create a virtual Composer package for WordPress. We give it a name, version and location to a zip file archive where it can be downloaded from.&lt;/p&gt;
&lt;p&gt;We don&amp;rsquo;t want the package to be installed to the default vendor directory that Composer would use. We need to specify a different directory. We do this with the aid of the webroot installer package. By giving our virtual package a type of &lt;code&gt;webroot&lt;/code&gt;, the plugin will detect and relocate the install location of WordPress to &lt;code&gt;public/wp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We define the preferred install located in the extra section of the &lt;code&gt;composer.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;We need to create the public directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir public
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It&amp;rsquo;s good practice to have a separate directory in your projects for your document root. This is so that if you have any other files, that shouldn&amp;rsquo;t be served via the web server, you can place them outside of the public directory.&lt;/p&gt;
&lt;p&gt;You can now run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;php composer.phar install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will pull down WordPress for you into the correct location.&lt;/p&gt;
&lt;p&gt;Now with a normal install you&amp;rsquo;d go ahead and proceed with the famous 5 minute install. But because we want to be able to use Composer for any future WordPress updates, we don&amp;rsquo;t want to change any of the contents of the &lt;code&gt;public/wp&lt;/code&gt; directory. We want to be able to ignore this directory with our source code management tool.&lt;/p&gt;
&lt;p&gt;In order to be able to use WordPress, we need to copy some files from the &lt;code&gt;public/wp&lt;/code&gt; directory to the public directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cp -R public/wp/{wp-content,index.php,wp-config-sample.php} public/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;mv public/wp-config-sample.php public/wp-config.php&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;public/index.php&lt;/code&gt;, modify the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;require( dirname( __FILE__ ) . &amp;#39;/wp-blog-header.php&amp;#39; );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;require( dirname( __FILE__ ) . &amp;#39;/wp/wp-blog-header.php&amp;#39; );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;rsquo;re just updating the path as we want to reference the core WordPress files in the &lt;code&gt;public/wp&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Go to &lt;a href="https://api.wordpress.org/secret-key/1.1/salt/"&gt;https://api.wordpress.org/secret-key/1.1/salt/&lt;/a&gt; and update the lines in your &lt;code&gt;public/wp-config.php&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;define(&amp;#39;AUTH_KEY&amp;#39;, &amp;#39;put your unique phrase here&amp;#39;);
define(&amp;#39;SECURE_AUTH_KEY&amp;#39;, &amp;#39;put your unique phrase here&amp;#39;);
define(&amp;#39;LOGGED_IN_KEY&amp;#39;, &amp;#39;put your unique phrase here&amp;#39;);
define(&amp;#39;NONCE_KEY&amp;#39;, &amp;#39;put your unique phrase here&amp;#39;);
define(&amp;#39;AUTH_SALT&amp;#39;, &amp;#39;put your unique phrase here&amp;#39;);
define(&amp;#39;SECURE_AUTH_SALT&amp;#39;, &amp;#39;put your unique phrase here&amp;#39;);
define(&amp;#39;LOGGED_IN_SALT&amp;#39;, &amp;#39;put your unique phrase here&amp;#39;);
define(&amp;#39;NONCE_SALT&amp;#39;, &amp;#39;put your unique phrase here&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;ll secure your WordPress install. Configure your database settings as you normally would.&lt;/p&gt;
&lt;p&gt;Now we need to set a few additional constants for the configuration.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;define&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WP_CONTENT_DIR&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;__DIR__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/wp-content&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;define&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WP_CONTENT_URL&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;_SERVER&lt;/span&gt;&lt;span class="cp"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SERVER_NAME&amp;#39;&lt;/span&gt;&lt;span class="cp"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/wp-content&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;define&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WP_SITEURL&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;_SERVER&lt;/span&gt;&lt;span class="cp"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SERVER_NAME&amp;#39;&lt;/span&gt;&lt;span class="cp"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/wp&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;define&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WP_HOME&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;_SERVER&lt;/span&gt;&lt;span class="cp"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SERVER_NAME&amp;#39;&lt;/span&gt;&lt;span class="cp"&gt;]&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Because the &lt;code&gt;wp-content&lt;/code&gt; directory isn&amp;rsquo;t in the same place as the core WordPress files (remember, it is now one directory level above), we need to tell the config file where it actually is. The same with the core WordPress files.&lt;/p&gt;
&lt;p&gt;Some other optional tidy up; remove the default &lt;code&gt;twenty*&lt;/code&gt; themes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;rm -rf public/wp-content/themes/twenty*
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Remove the default Hello Dolly plugin too:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;rm public/wp-content/plugins/hello.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You probably have an idea of what theme you&amp;rsquo;ll be using. Setting this constant will define the default theme, so that you don&amp;rsquo;t need to manually set this in your admin. This is optional.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;define(&amp;#39;WP_DEFAULT_THEME&amp;#39;, &amp;#39;mytheme&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Regarding housekeeping with your source code management tool. You&amp;rsquo;d want to ignore the &lt;code&gt;composer.phar&lt;/code&gt; file and &lt;code&gt;public/wp&lt;/code&gt; directory. Everything else can be committed and pushed.&lt;/p&gt;
&lt;h2&gt;Updating WordPress&lt;/h2&gt;
&lt;p&gt;Say you want to update to version &lt;code&gt;4.0.1&lt;/code&gt; when it is released. In your &lt;code&gt;composer.json&lt;/code&gt; file, update the section under repositories so it looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;package&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;package&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wordpress&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;webroot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;4.0.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;dist&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;zip&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://github.com/WordPress/WordPress/archive/4.0.1.zip&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;require&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fancyguy/webroot-installer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;rsquo;ve updated the version number and the URL for the zip archive to reference the new versioned file.&lt;/p&gt;
&lt;p&gt;You can then run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;php composer.phar update wordpress
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then commit your &lt;code&gt;composer.json&lt;/code&gt; and &lt;code&gt;composer.lock&lt;/code&gt; files.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all there is to it. This is quite a stable workflow, and my next blog posts will cover handling the installation of plugins and themes.&lt;/p&gt;</content></entry><entry><title>Introduction to Ansible</title><link href="https://davidwinter.dev/2013/11/23/introduction-to-ansible/" rel="alternate"/><published>2013-11-23T00:00:00+00:00</published><updated>2013-11-23T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2013-11-23:/2013/11/23/introduction-to-ansible/</id><summary type="html">&lt;p&gt;The new, cool provisioning kid on the block&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;ve been using Ansible now for just under six months. I love it. I used to use Puppet religlously, but with a change of job, I needed something simple to setup, to work with a range of different servers, and be easy for others to learn.&lt;/p&gt;
&lt;p&gt;Puppet is very powerful, and I was very happy with it. I still use it for some of my projects, because it just doesn&amp;rsquo;t make sense to switch them over to Ansible unless there is a specific reason that warrants rewriting the manifests.&lt;/p&gt;
&lt;p&gt;You may think Puppet will win over people who manage multiple servers, and that maybe Ansible can&amp;rsquo;t handle this&lt;sup&gt;&lt;a href="#update"&gt;*&lt;/a&gt;&lt;/sup&gt;. You&amp;rsquo;d be absolutely wrong to make that assumption. Ansible is known to be used in setups managing in the range of 20,000 nodes. Ansible does&amp;rsquo;t require a complex master-slave setup, as Puppet does, that takes in itself hours to setup. And it&amp;rsquo;s coped perfectly with any setup I&amp;rsquo;ve encountered so far.&lt;/p&gt;
&lt;p&gt;Provide Ansible with a list of machines to provision, and the specifics and it&amp;rsquo;ll just go ahead and do it.&lt;/p&gt;
&lt;p&gt;Lets dive in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I&amp;rsquo;m using Vagrant for this demo. Though, all of the Ansible specific parts are not dependent on it.&lt;/p&gt;
&lt;p&gt;Also, at time of writing, I&amp;rsquo;m using Vagrant 1.3.5 and Ansible 1.3.4.&lt;/p&gt;
&lt;p&gt;Install Ansible with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo easy_install pip
sudo pip install -U ansible
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Get a base Ubuntu machine up and running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir ansible-demo
cd ansible-demo
vagrant init precise64 http://files.vagrantup.com/precise64.box
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;rsquo;ll want to give the machine a dedicated IP address that we can have Ansible connect to, so in your &lt;code&gt;Vagrantfile&lt;/code&gt;, ensure you have the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;config.vm.network :private_network, ip: &amp;quot;192.168.33.20&amp;quot;

config.vm.provision :ansible do |ansible|
  ansible.playbook = &amp;quot;private/ansible/site.yml&amp;quot;
  ansible.inventory_path = &amp;quot;private/ansible/development&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;rsquo;ve also told Vagrant that we want to use Ansible to provision our box.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s create the directory structure for Ansible:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir -p private/ansible
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now to tell Ansible about the machine we want it to provision. Add the following file &lt;code&gt;private/ansible/development&lt;/code&gt; and add the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[development]&lt;/span&gt;
&lt;span class="na"&gt;192.168.33.20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This adds our new Vagrant machine to the &lt;code&gt;development&lt;/code&gt; group. We specify it&amp;rsquo;s IP address so Ansible knows how to connect to it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; An inventory file isn&amp;rsquo;t actually required for Vagrant—it would create one automatically for us if we hadn&amp;rsquo;t—however, it&amp;rsquo;s a core part of Ansible, so worth using it with an explanation.&lt;/p&gt;
&lt;p&gt;Now we&amp;rsquo;ll tell Ansible how to provision our Vagrant machine. Create the file &lt;code&gt;private/ansible/site.yml&lt;/code&gt; and inside it add:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;---
&lt;span class="k"&gt;-&lt;/span&gt; hosts: all
  sudo: yes
  tasks:
    &lt;span class="k"&gt;-&lt;/span&gt; name: Update Apt cache
      apt: update_cache=yes

    &lt;span class="k"&gt;-&lt;/span&gt; name: Install Apache
      apt: pkg=apache2 state=present
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Lets get the machine up and running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;vagrant up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After a while, you should see some output like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;provisioner&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ansible&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;PLAY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;********************************************************************&lt;/span&gt;

&lt;span class="n"&gt;GATHERING&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FACTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;***************************************************************&lt;/span&gt;
&lt;span class="nl"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;192.168.33.20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nl"&gt;TASK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Apt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;******************************************************&lt;/span&gt;
&lt;span class="nl"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;192.168.33.20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nl"&gt;TASK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Apache&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;********************************************************&lt;/span&gt;
&lt;span class="nl"&gt;changed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;192.168.33.20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;PLAY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RECAP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;********************************************************************&lt;/span&gt;
&lt;span class="mf"&gt;192.168.33.20&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you now visit &lt;a href="http://192.168.33.20"&gt;http://192.168.33.20&lt;/a&gt; in your browser, you should see the amazing &amp;ldquo;It works!&amp;rdquo; Apache default host file.&lt;/p&gt;
&lt;p&gt;If you hadn&amp;rsquo;t noticed already, &lt;code&gt;site.yml&lt;/code&gt; is written in YAML. To run through the &lt;code&gt;site.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;- hosts: all
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This allows you to target specific groups for Anible to apply rules to. We&amp;rsquo;ve used the &lt;code&gt;development&lt;/code&gt; group in the &lt;code&gt;private/ansible/development&lt;/code&gt; file. You could also have &lt;code&gt;webservers&lt;/code&gt;, &lt;code&gt;databases&lt;/code&gt;, etc. For our introduction, we&amp;rsquo;ll just tell Ansible to target all hosts.&lt;/p&gt;
&lt;p&gt;As we&amp;rsquo;re installing packages on Ubuntu, we need &lt;code&gt;root&lt;/code&gt; privileges, so we tell Ansible to use &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next up we define a bunch of tasks to run. Tasks use Ansible modules to apply things to the machine. Each task you give a descriptive name which is used in the output when Ansible runs. Be as descriptive as possible.&lt;/p&gt;
&lt;p&gt;We use the &lt;code&gt;apt&lt;/code&gt; module. First of all, we tell Apt to update it&amp;rsquo;s cache so that it can install new packages.&lt;/p&gt;
&lt;p&gt;Then we get the &lt;code&gt;apache2&lt;/code&gt; package installed. We tell Ansible to ensure it&amp;rsquo;s &lt;code&gt;present&lt;/code&gt; so that on subsequent runs, it doesn&amp;rsquo;t need to try and install it again.&lt;/p&gt;
&lt;p&gt;So&amp;hellip; the Apache &amp;lsquo;It works!&amp;rsquo; page isn&amp;rsquo;t that much fun. Lets get PHP up and running.&lt;/p&gt;
&lt;p&gt;Create a file called &lt;code&gt;test.php&lt;/code&gt; in the directory &lt;code&gt;private/ansible/files&lt;/code&gt; with the contents:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="nb"&gt;phpinfo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;At the bottom of &lt;code&gt;site.yml&lt;/code&gt; we&amp;rsquo;ll include some more tasks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;

&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PHP&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;libapache2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;php5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;present&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We have two new tasks here. The first will copy the local &lt;code&gt;test.php&lt;/code&gt; file to the remote machine into the specified destination. We then install the PHP module for Apache.&lt;/p&gt;
&lt;p&gt;If we were to provision this now with Ansible, the packages would be installed and the file would be copied, however, we need to restart Apache so that it loads the PHP module.&lt;/p&gt;
&lt;p&gt;We do this in Ansible with handlers.&lt;/p&gt;
&lt;p&gt;At the bottom of &lt;code&gt;site.yml&lt;/code&gt; add the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;handlers:
  - name: Restart Apache
    service: name=apache2 state=restarted
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We then want to reference this handler when we install the PHP module. Update the PHP &lt;code&gt;apt&lt;/code&gt; task to be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;- name: Install PHP
  apt: pkg=libapache2-mod-php5 state=present
  notify: Restart Apache
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;rsquo;ve added the &lt;code&gt;notify&lt;/code&gt; part to the task. This will tell Ansible to run the &lt;code&gt;Restart Apache&lt;/code&gt; handler when PHP is installed, which in turn will restart the Apache server making PHP become available.&lt;/p&gt;
&lt;p&gt;At this stage it&amp;rsquo;s safe to run &lt;code&gt;vagrant provision&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once this has run, you&amp;rsquo;ll be able to visit &lt;a href="http://192.168.33.20/test.php"&gt;http://192.168.33.20/test.php&lt;/a&gt; and you should see a PHP info page.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s nice. But we&amp;rsquo;ll be a bit more exciting.&lt;/p&gt;
&lt;p&gt;In your &lt;code&gt;Vagrantfile&lt;/code&gt; lets mount out Vagrant project to the virtual machine so that we can use files in our project. Add this below the &lt;code&gt;:private_network&lt;/code&gt; line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;config.vm.synced_folder &amp;quot;.&amp;quot;, &amp;quot;/vagrant&amp;quot;, :nfs =&amp;gt; true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This mounts our Vagrant project directory, denoted by the period &lt;code&gt;.&lt;/code&gt; and on the virtual machine, mounts it to &lt;code&gt;/vagrant&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Create a new file called &lt;code&gt;wordpress.conf&lt;/code&gt; and put it inside the &lt;code&gt;private/ansible/files&lt;/code&gt; directory with the following contents:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;VirtualHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*:80&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;DocumentRoot&lt;span class="w"&gt; &lt;/span&gt;/vagrant/public
&lt;span class="w"&gt;    &lt;/span&gt;ServerName&lt;span class="w"&gt; &lt;/span&gt;wordpress.dev
&lt;span class="nt"&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Go to WordPress.org and download the latest version. Extract the files and move the &lt;code&gt;wordpress&lt;/code&gt; directory into your project and rename it to &lt;code&gt;public&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now add the following to your &lt;code&gt;site.yml&lt;/code&gt; file below where we installed PHP:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;-&lt;/span&gt; name: WordPress virtualhost
  copy:
    src: files/wordpress.conf
    dest: /etc/apache2/sites-available/wordpress.conf

&lt;span class="k"&gt;-&lt;/span&gt; name: Enable WordPress virtualhost
  file:
    src: /etc/apache2/sites-available/wordpress.conf
    dest: /etc/apache2/sites-enabled/wordpress
    state: link
  notify: Restart Apache

&lt;span class="k"&gt;-&lt;/span&gt; name: Disable default Apache virtualhost
  file:
    dest: /etc/apache2/sites-enabled/000-default
    state: absent

&lt;span class="k"&gt;-&lt;/span&gt; name: Install MySQL
  apt: pkg=mysql-server state=present

&lt;span class="k"&gt;-&lt;/span&gt; name: Install python-mysqldb
  apt: pkg=python-mysqldb state=present

&lt;span class="k"&gt;-&lt;/span&gt; name: Install PHP MySQL bindings
  apt: pkg=php5-mysql state=present
  notify: Restart Apache

&lt;span class="k"&gt;-&lt;/span&gt; name: Setup WordPress database
  mysql_db: name=wordpress state=present
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It should be pretty clear what this does by just reading the &lt;code&gt;name&lt;/code&gt; titles for each task! However, I&amp;rsquo;ll explain two of them.&lt;/p&gt;
&lt;p&gt;We disable the default Apache virtual host so that we don&amp;rsquo;t have to worry about setting up a hostname in our &lt;code&gt;/etc/hosts&lt;/code&gt; file. This is something you&amp;rsquo;ll more than likely do when you have a few different projects on your machine, but we&amp;rsquo;ll skip that for this demo.&lt;/p&gt;
&lt;p&gt;We also install the &lt;code&gt;python-mysqldb&lt;/code&gt; package. This is installed so that Ansible can then create databases for us with the &lt;code&gt;mysql_db&lt;/code&gt; task. It&amp;rsquo;s an Ansible dependency that we have to include so that we get to use Ansible more.&lt;/p&gt;
&lt;p&gt;Because we&amp;rsquo;ve changed the &lt;code&gt;Vagrantfile&lt;/code&gt; we can&amp;rsquo;t just do a &lt;code&gt;vagrant provision&lt;/code&gt; - we need to actually reboot the machine so that Vagrant can mount the &lt;code&gt;/vagrant&lt;/code&gt; directory share. Because we&amp;rsquo;re using NFS for this, it&amp;rsquo;ll need &lt;code&gt;sudo&lt;/code&gt; privileges, so you may be prompted for your password.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;vagrant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once the machine is running again, provision with Ansible:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;vagrant provision
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can now visit &lt;a href="http://192.168.33.20"&gt;http://192.168.33.20&lt;/a&gt; and you should be preented with a WordPress installer. That&amp;rsquo;s it. Very little effort. You can use the default MySQL credentials to setup Wordpress:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Host: &lt;code&gt;localhost&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;User: &lt;code&gt;root&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Password: leave this blank&lt;/li&gt;
&lt;li&gt;Database: &lt;code&gt;wordpress&lt;/code&gt; - this is what we specified in our &lt;code&gt;site.yml&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We&amp;rsquo;re not worrying about securing MySQL. This is just a development virtual machine, so we don&amp;rsquo;t have to worry about it. That&amp;rsquo;s why we use the &lt;code&gt;root&lt;/code&gt; account with no password.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a very quick, brief introduction to Ansible. In my next post, I&amp;rsquo;ll talk more about reusable Ansible tasks - roles.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Some very helpful websites to have in your arsenal when working with Ansible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://packages.ubuntu.com/"&gt;Ubuntu Packages&lt;/a&gt; for finding package names to use to install. Be sure to select &lt;code&gt;Precise&lt;/code&gt; as your Ubuntu version which is Ubuntu 12.04 LTS&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.ansibleworks.com/docs/modules.html"&gt;Ansible Modules documentation&lt;/a&gt; has all of the references for modules you can use&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a name="update"&gt;&lt;/a&gt;&lt;strong&gt;Update:&lt;/strong&gt; Michael DeHaan—creator of Ansible—thought I should clarify my original sentence. Quite rightly so, as it could have been misinterpreted that I was suggesting Ansible couldn&amp;rsquo;t handle complex/large/master-slave setups. It can do all of them. The point I was trying to make is that it&amp;rsquo;s something Puppet users may think it can&amp;rsquo;t, and that they could make decisions not to use Ansible because of a misunderstanding.&lt;/p&gt;
&lt;blockquote align="center" class="twitter-tweet" lang="en"&gt;&lt;p&gt;&lt;a href="https://twitter.com/davidwinter"&gt;@davidwinter&lt;/a&gt; &amp;quot;and that maybe Ansible can’t handle this&amp;quot; ... might wish to clarify we have users in the 10k-20k node range, etc :)&lt;/p&gt;&amp;mdash; Michael DeHaan (@laserllama) &lt;a href="https://twitter.com/laserllama/statuses/404715981131378688"&gt;November 24, 2013&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;</content></entry><entry><title>Poor mans VPN with sshuttle</title><link href="https://davidwinter.dev/2013/08/10/poor-mans-vpn/" rel="alternate"/><published>2013-08-10T00:00:00+01:00</published><updated>2013-08-10T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2013-08-10:/2013/08/10/poor-mans-vpn/</id><summary type="html">&lt;p&gt;Get around those evil firewalls and secure your net connection&lt;/p&gt;</summary><content type="html">&lt;p&gt;It was far too hot in the office the other week and I needed some place a little cooler to work so I could keep focused. I sought refuge at the &lt;a href="http://www.campuslondon.com/"&gt;Google Campus&lt;/a&gt; in London which has glorious a/c and a&amp;ndash;surprise surprise&amp;ndash;super fast internet connection.&lt;/p&gt;
&lt;p&gt;However, being in a basement full of geeks, using Google&amp;rsquo;s wifi, and not encrypting your connection, is quite a risky thing to do. I get paranoid about people sniffing my traffic.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a subscriber to &lt;a href="https://www.privateinternetaccess.com/"&gt;Private Internet Access&lt;/a&gt;, which is a VPN provider. I use that with OpenVPN using &lt;a href="https://code.google.com/p/tunnelblick/"&gt;Tunnelblick&lt;/a&gt; for OS X. I&amp;rsquo;ve been using it fine for ages and have had no issues. Google doesn&amp;rsquo;t appear to like me encrypting my traffic. I&amp;rsquo;m able to connect to PIA, but after a while, my wifi connection drops. And then I&amp;rsquo;m not able to reconnect to Wifi unless I restart my Mac. I&amp;rsquo;ve never had this issue before or anywhere else.&lt;/p&gt;
&lt;p&gt;Setting up an SSH SOCKS proxy has always been quite reliable and easy way to setup an encrypted connection. I&amp;rsquo;ve used it for bypassing my old University&amp;rsquo;s firewall so I could &lt;a href="/2006/02/06/using-irc-and-other-im-apps-at-university"&gt;connect to IRC&lt;/a&gt;. Also, for getting around &lt;a href="/2010/06/19/using-o2-payg-mobile-broadband"&gt;annoying image compression&lt;/a&gt; on my old 3G connection from o2. Though recently I&amp;rsquo;ve noticed not all traffic is guaranteed to go over the SOCKS proxy, so it&amp;rsquo;s not as secure as using a VPN.&lt;/p&gt;
&lt;p&gt;After lunch, I moved onto &lt;a href="http://www.wearetbc.com/"&gt;The Book Club&lt;/a&gt;. The wifi was no way near as fast, but the food in there is amazing! They also had an annoying Firewall setup. I couldn&amp;rsquo;t connect to PIA via the VPN either. I setup the SOCKS proxy again but because not all of the traffic goes over the proxy, apps such as Spotify, Hipchat and some others just didn&amp;rsquo;t want to work. Not having some sort of encryption wasn&amp;rsquo;t an option.&lt;/p&gt;
&lt;p&gt;With a bit of Googling, I come across &lt;a href="https://github.com/apenwarr/sshuttle"&gt;sshuttle&lt;/a&gt;. It&amp;rsquo;s written in Python and does some fancy SSH&amp;rsquo;ing, and allows you to route all traffic over it, without the need of setting up an SSH SOCKS proxy.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;brew install sshuttle
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You just run the command, and it just works. It&amp;rsquo;s amazingly simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sshuttle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--dns -vvr david@my.remote.server.com 0/0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Just replace &lt;code&gt;david@my.remote.server.com&lt;/code&gt; with your remote server that you can SSH into. &lt;code&gt;sshuttle&lt;/code&gt; will handle the rest. When you&amp;rsquo;re done with the connection, just &lt;code&gt;CTRL&lt;/code&gt; + &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;</content></entry><entry><title>Switch to a retro shell, Fish shell</title><link href="https://davidwinter.dev/2013/08/04/switch-to-a-retro-shell-fish-shell/" rel="alternate"/><published>2013-08-04T00:00:00+01:00</published><updated>2013-08-04T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2013-08-04:/2013/08/04/switch-to-a-retro-shell-fish-shell/</id><summary type="html">&lt;p&gt;Leave behind the millions of plugins, and slowness, and just use Fish&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;ve been using &lt;a href="http://fishshell.com/"&gt;fish shell&lt;/a&gt; for the last year, and would never go back to using &lt;code&gt;bash&lt;/code&gt; or &lt;code&gt;zsh&lt;/code&gt; again. Ever.&lt;/p&gt;
&lt;p&gt;All I want is for my shell to be speedy, and helpful. As standard. Without the need to install a mountain of plugins, or have a 200 line configuration file.&lt;/p&gt;
&lt;p&gt;Fish is perfect for me. And I&amp;rsquo;m sure it&amp;rsquo;ll be a perfect match for you too. Some highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Invalid commands; if you mistype &lt;code&gt;mkdir&lt;/code&gt; and type in &lt;code&gt;mkdi&lt;/code&gt; or something similar, the command will appear in red. Instant feedback.&lt;/li&gt;
&lt;li&gt;Valid filepaths appear underlined.&lt;/li&gt;
&lt;li&gt;Autosuggest; while typing a command, autosuggest will appear in grey to the right of your cursor.&lt;/li&gt;
&lt;li&gt;Autosuggest knows about paths and options, and will also pull in your history too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your config is in a bit of an obscure location (the only negative I can think of) at &lt;code&gt;~/.config/fish/fish.config&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re moving from &lt;code&gt;bash&lt;/code&gt; or &lt;code&gt;zsh&lt;/code&gt;, probably the most important thing you&amp;rsquo;ll want to set, is your &lt;code&gt;$PATH&lt;/code&gt; variable. Here&amp;rsquo;s how in &lt;code&gt;fish&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;set PATH &amp;quot;/usr/local/bin&amp;quot; $PATH
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is just prefixing &lt;code&gt;/usr/local/bin&lt;/code&gt; to the front of my &lt;code&gt;$PATH&lt;/code&gt; so my &lt;code&gt;homebrew&lt;/code&gt; works.&lt;/p&gt;
&lt;p&gt;Set your default &lt;code&gt;EDITOR&lt;/code&gt;?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;set -g -x EDITOR vim
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Want to display your current branch when in either a git or Mercurial repo?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;git_prompt&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;set_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normal&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39; on &amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;set_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;magenta&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;%s&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;currentbranch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;set_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normal&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;hg_prompt&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;set_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normal&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39; on &amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;set_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;magenta&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;%s&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;set_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normal&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;fish_prompt&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;set_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="n"&gt;fish_color_cwd&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;%s&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt_pwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;set_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normal&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;git_prompt&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;hg_prompt&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39; &amp;gt;: &amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This gives you a really clean prompt with just a retro Lost looking &lt;code&gt;&amp;gt;:&lt;/code&gt; prompt.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s not really much else I want to write about. This was more of a &amp;lsquo;spread the word&amp;rsquo;, evangelical post. Just take the dive, and switch. You won&amp;rsquo;t regret it.&lt;/p&gt;
&lt;p&gt;Go and read more in the &lt;a href="http://fishshell.com/tutorial.html"&gt;fish tutorial&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Identity theft and no one seeming to care but me</title><link href="https://davidwinter.dev/2013/04/09/identity-theft-and-no-one-seeming-to-care-but-me/" rel="alternate"/><published>2013-04-09T00:00:00+01:00</published><updated>2013-04-09T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2013-04-09:/2013/04/09/identity-theft-and-no-one-seeming-to-care-but-me/</id><summary type="html">&lt;p&gt;Maybe don&amp;rsquo;t waste your time reporting it in future&amp;hellip;&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;This post is a little out of the ordinary for my blog - well, OK, quite a bit. But I thought it was worth posting in the hope that other people who have had this happen to them can get in touch. If you&amp;rsquo;re expecting another tech related post, don&amp;rsquo;t bother to continue reading!&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I woke up last Thursday to a letter in the post from Vodafone. Strange I thought, seeing as though I had cancelled my contract with them ages ago and was now on a new network.&lt;/p&gt;
&lt;p&gt;The letter was a confirmation of setting up a direct debit. It had my name and address (obviously). The bank account used for the direct debit was in my name, however the sort code and account number weren&amp;rsquo;t mine. So that was a relief right away knowing that my account hadn&amp;rsquo;t been drained.&lt;/p&gt;
&lt;p&gt;Someone had ordered a phone using my name and address, and either setup a bank account in my name, used some other poor persons or just faked the details.&lt;/p&gt;
&lt;p&gt;I did a search for the bank via the sort code which resulted in a Derby branch of Lloyds TSB. I definitely don&amp;rsquo;t have a Lloyds account and don&amp;rsquo;t think I&amp;rsquo;ve ever been to Derby.&lt;/p&gt;
&lt;p&gt;Visited the Vodafone website and saw that they had online live chat. Not had much success with these previously&amp;ndash;usually someone in an office reading off a script&amp;ndash;never usually helpful. I let the support person know the situation. The letter had on it the account number of this new account so I gave them that. They were able to block the account and the phone within a few minutes.&lt;/p&gt;
&lt;p&gt;They were also able to tell me that the phone had been bought in a shopping centre local to where I live. &lt;em&gt;Interesting.&lt;/em&gt; Not just some random scammer in a far away town, but actually someone in close proximity to me. I straight away thought someone had been through my rubbish and got my details from that, but then reflected thinking how paranoid I am about these sorts of things, and therefore shred 99.9% of all post I receive. There was a possibility someone had found something of mine, but a low one I think. So then my mind wanders to think perhaps it is someone I know. Lots of people know my address, I have a few &amp;lsquo;enemies&amp;rsquo;, and considering how close the shopping centre is to me that the phone was bought at, I think that is a higher probability.&lt;/p&gt;
&lt;p&gt;I asked the live chat person how someone can buy a phone in a retail store. They said they&amp;rsquo;d need some sort of ID with them. I asked whether that may be photo ID and they said yes. The stores make a copy of these when the purchase is made. So if someone had used photo ID it&amp;rsquo;d have been with their face and my name on it.&lt;/p&gt;
&lt;p&gt;The support person suggested I go to the store and talk to the Manager there to see the ID, beacuse I said it may be someone I know. Also the store would most likely have CCTV and I had the time and date the purchase was made. Surely a simple case of reviewing the CCTV footage and asking me to see if I recognised the person.&lt;/p&gt;
&lt;p&gt;The support person (Shakib K) was so very helpful. I was surprised&amp;mdash;but grateful&amp;mdash;that I was able to contact someone so quickly and painlessly. The Vodafone account had been blocked and the support person had submitted an internal fraud report to Vodafone that would be investigated, and I passed on my details so they could contact me.&lt;/p&gt;
&lt;p&gt;Before heading to the Vodafone store, I tweeted Lloyds TSB asking them who I should contact about the fraud. The first reply I had just said I needed to go into a branch. Unhelpful and not convienient considering I&amp;rsquo;m trying to help them and their customer. I replied back asking if there was a telephone number I could contact. I got another reply with a number to call, which I did.&lt;/p&gt;
&lt;p&gt;I explained the situation, gave them the sort code and account number. Interestingly, the name they had for the account wasn&amp;rsquo;t mine, but someone elses. So someone hadn&amp;rsquo;t created a fake account of mine, but was instead using someone elses. But how the hell was Vodafone and Lloyds TSB able to create the direct debit if the names of the account holder didn&amp;rsquo;t match? Surely something is wrong with that process. Sounds so easy for the criminal to do.&lt;/p&gt;
&lt;p&gt;When I suggested to them that they should contact the account holder to make them aware that someone may be using their bank account to steal money, they said they coudln&amp;rsquo;t do anything. Nothing at all. Zip.&lt;/p&gt;
&lt;p&gt;Ridiculous.&lt;/p&gt;
&lt;p&gt;I suggested that they should see if a Vodafone direct debit existed on the account and should cancel it. I had the date the confirmation had been made.&lt;/p&gt;
&lt;p&gt;Nope, couldn&amp;rsquo;t do that either. They said I had to go into a branch and report it.&lt;/p&gt;
&lt;p&gt;What the hell? You have someone calling them up, at what I assume was their fraud department, or something similar, explaining that a dodgy direct debit had been setup on an account of theirs, and they don&amp;rsquo;t do anything? No action would be taken.&lt;/p&gt;
&lt;p&gt;They expect the person reporting it to go out of their way, waste their time reporting it? Yes, I wouldn&amp;rsquo;t have minded, but after the unhelpful responses on twitter and on the phone, I decided against it. I had pleaded with them to at least flag the account. But they wouldn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;I understand they can&amp;rsquo;t delete the direct debit just because I called up. I understand they can&amp;rsquo;t just phone the customer and say someone has phoned up saying money has been taken out of their account. But they could at least add a note to the account so that if the account holder does call up, they have some information or clue as to why money has been stolen from them. They could at least write a letter saying that they suspect someone has setup a fraudulent direct debit. The account holder could at least then check to see if that is the case, and call them to get assistance, or ignore it if nothing of the sort has happened.&lt;/p&gt;
&lt;p&gt;Wouldn&amp;rsquo;t you like your bank to tell you as soon as possible if their is something suspicious? Or someone has reported something? I sure as hell would.&lt;/p&gt;
&lt;p&gt;Lloyds TSB didn&amp;rsquo;t seem to be concerned at all, and weren&amp;rsquo;t bothered about their customer. They obviously prefer to be reactive rather than proactive in supporting their customers. I certainly won&amp;rsquo;t bank with them, or recommend them to anyone in the future.&lt;/p&gt;
&lt;p&gt;So after that useless help from Lloyds TSB, I made my way to the Vodafone store. I took the letter with me, took my passport and a utility bill so that I had some genuine proof of ID with me.&lt;/p&gt;
&lt;p&gt;I got to the store and had to wait around 10 minutes to see the manager. I explained the situation, and said that the online chat Vodafone rep had suggested I come to the store. I offered to show them the letter but the manager didn&amp;rsquo;t seem that interested. Because I had told them that no money had been stolen from me personally, that they couldn&amp;rsquo;t show me the ID used to make the purchase. Even though this was someone who had impersonated me and I had the letter to prove it. I was one of the victims.&lt;/p&gt;
&lt;p&gt;I had had such excellent support from the online chat staff, but the feeling I got from the manager was that he wasn&amp;rsquo;t bothered at all. He obviously seems to prefer spending more time and care for people impersonating and stealing from others, than someone trying to report the situation and help apprehend and prosecute the criminal. Crazy.&lt;/p&gt;
&lt;p&gt;The Police station was very close to the shopping centre, so I decided to go their to report the incident. I was aware that there was an online form to do the same thing, but because the shopping centre was so close to me, I thought the local police might be interested as it could possibly be someone I know. I ended up waiting 30 minutes and the desk clerk telling me to report it online. Dead end there. More time wasted.&lt;/p&gt;
&lt;p&gt;Disillusioned, I head back home and look at the online fraud reporting form. At the very start, it says that the submission may not result in the crime being investigated. Oh that really encourages me to waste more time filling out the form to try and help catch a criminal. At least spring it on me at the end of me completing the form! Regardless, I completed the form. I got a crime number but I don&amp;rsquo;t expect anything to become of it.&lt;/p&gt;
&lt;p&gt;The annoying thing is that there is probably CCTV evidence of the culprit in the Vodafone store, and a copy of the fake photo ID that was used. Isn&amp;rsquo;t that solid evidence and enough to get a prosecution? I&amp;rsquo;d have thought so. I thought it was worth 5 hours of my time chasing around reporting things to different people, but other parties obviously don&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;OK, maybe I wouldn&amp;rsquo;t recognise the person on the CCTV or photo ID, but isn&amp;rsquo;t it worth a shot? And if not, why can&amp;rsquo;t Vodafone or the Police post the picture online? It may only be small fish, but if you get a positive ID from someone, arrest the individual and maybe it&amp;rsquo;ll put them on the right path or just simply prevent them from doing it again in the future.&lt;/p&gt;
&lt;p&gt;By not doing anything, you encourage them to steal more, and encourage me less to report anything in the future - to the Police or companies involved. It&amp;rsquo;s completely backwards and not a good outlook for the future of peoples confidence in reporting crime.  &lt;/p&gt;</content></entry><entry><title>Setting up a Puppet Master and Agents on EC2</title><link href="https://davidwinter.dev/2012/12/08/setting-up-puppet-master-and-agents-on-ec2/" rel="alternate"/><published>2012-12-08T00:00:00+00:00</published><updated>2012-12-08T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2012-12-08:/2012/12/08/setting-up-puppet-master-and-agents-on-ec2/</id><summary type="html">&lt;p&gt;One server to rule them all&lt;/p&gt;</summary><content type="html">&lt;p&gt;Now you&amp;rsquo;ve mastered how to use the &lt;a href="/2012/12/07/install-ec2-command-line-tools-with-os-x"&gt;EC2 command line tools&lt;/a&gt; (Ninja, right?), you&amp;rsquo;ll want to manage all of those newly created instances in the easiest way possible. Puppet is the answer. If you&amp;rsquo;re not familiar with Puppet, back in March I wrote an &lt;a href="/2012/03/04/introduction-to-puppet/"&gt;introduction to it&lt;/a&gt; which would be good to read before continuing. If you are familiar, read on.&lt;/p&gt;
&lt;p&gt;Previously I&amp;rsquo;ve only used Puppet &amp;lsquo;agentless&amp;rsquo;, or simply, standalone. This is great for developing small sites that don&amp;rsquo;t require multiple instances, however with larger projects, you&amp;rsquo;ll need a master so that you can leave that to deal with the &amp;lsquo;agents&amp;rsquo; that connect to it.&lt;/p&gt;
&lt;h2&gt;Master and Agents&lt;/h2&gt;
&lt;p&gt;The example we&amp;rsquo;ll use for this post is for a web hosting project. You want to create a new instance for each customers, with a web server and database. Those packages will be installed and configured centrally from one master server so that all the instances are identical in that sense.&lt;/p&gt;
&lt;p&gt;When first connecting an agent to a master, they have to exchange SSL certificates so that they know who is talking to who. The default way to do this is to manually check and sign the requests of agents as they attempt to connect to the master. This is time consuming an inefficient.&lt;/p&gt;
&lt;p&gt;Instead, we&amp;rsquo;ll tell the Puppet master to automatically sign all incoming agent requests. That may sound like a security risk because anyones Puppet agent instance could try and connect. But we&amp;rsquo;ll use EC2 security groups to protect our server. For each new web server instance we create, we&amp;rsquo;ll assign it a security group called &lt;code&gt;puppets&lt;/code&gt;. Then on our Puppet master, we&amp;rsquo;ll only allow other instances to connect to Puppet who are in the &lt;code&gt;puppets&lt;/code&gt; group. This means we can safely allow the master to auto-sign requests, knowing that only our web server instances are allowed to do so.&lt;/p&gt;
&lt;h2&gt;The Puppet master&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll need to configure the master so that it&amp;rsquo;s ready to auto-sign puppet agents.&lt;/p&gt;
&lt;h3&gt;IP address and DNS&lt;/h3&gt;
&lt;p&gt;We need a dedicated Elastic IP for our Puppet master:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;allocate&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The output of that command will print out an IP address. It&amp;rsquo;s not currently associated to an instance, but it&amp;rsquo;s there ready to associate.&lt;/p&gt;
&lt;p&gt;Each Elastic IP address is also given a public facing DNS name. It&amp;rsquo;s in the format of:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-&amp;lt;IP-ADDRESS&amp;gt;.&amp;lt;REGION&amp;gt;.compute.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So if the IP we were allocated was 123.456.789.012 and we are using the &lt;code&gt;eu-west-1&lt;/code&gt; EC2 region, the DNS name would look like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-123-456-789-012.eu-west-1.compute.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The periods in the IP address have been replaced with dashes.&lt;/p&gt;
&lt;p&gt;The clever thing with these DNS names is that when you use them to communicate between EC2 instances, the DNS name resolves to the private IP address of the instance associated to it. This means you&amp;rsquo;re keeping the traffic internal to EC2 and it&amp;rsquo;s not going out onto the internet.&lt;/p&gt;
&lt;p&gt;Why&amp;rsquo;s this important? Because when you stop an instance, the IP is unassociated from it, and next time you start the instance, the private IP address is not guaranteed to be the same. Using the DNS name, you know it&amp;rsquo;ll always use the correct private IP address by the DNS name being resolved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To make your systems more flexible in future, and not so tied to a DNS name with an IP address in it, it&amp;rsquo;s worth setting up a DNS &lt;code&gt;CNAME&lt;/code&gt; record on your domain that forwards onto the Elastic IP DNS name, such as &lt;code&gt;puppetmaster.mydomain.com&lt;/code&gt;. That way, in your systems, you&amp;rsquo;re using your domain name, and you only then need to change the DNS &lt;code&gt;CNAME&lt;/code&gt; record in future if you change the Elastic IP.&lt;/p&gt;
&lt;h3&gt;Security groups and key pair&lt;/h3&gt;
&lt;p&gt;Create the security group that our Puppet agents will use.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-create-group puppets -d &amp;quot;Puppet agents&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Don&amp;rsquo;t worry about assigning ports to this group yet, at this stage, we just need to ensure it exists.&lt;/p&gt;
&lt;p&gt;Now create the security group for the Puppet master:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-create-group puppetmaster -d &amp;quot;Puppet master&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For the &lt;code&gt;puppetmaster&lt;/code&gt; group we want to allow TCP port &lt;code&gt;8140&lt;/code&gt; to only the &lt;code&gt;puppets&lt;/code&gt; security group:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-authorize -P tcp -p 8140 -o puppets puppetmaster
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;rsquo;ll throw in SSH too as it&amp;rsquo;s always handy to login just to see how things are:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-authorize -P tcp -p 22 puppetmaster
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Generate a new key pair for the master, and save it to a file, and set permissions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-create-keypair puppetmaster | sed 1d &amp;gt; puppetmaster.key
chmod 600 puppetmaster.key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Master instance and setup&lt;/h3&gt;
&lt;p&gt;Almost ready to create the instance, but when we initially do, it&amp;rsquo;ll be a base install of Ubuntu with packages that we need not installed, such as Puppet master.&lt;/p&gt;
&lt;p&gt;A great feature of EC2 is that of user data scripts. These are scripts that are run when the instance is first created. We need to create a script that installs and configures Puppet master.&lt;/p&gt;
&lt;p&gt;Create the following file and call it &lt;code&gt;puppetmaster.sh&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;-x
&lt;span class="nv"&gt;EC2_HOSTNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ec2-123-456-789-012.eu-west-1.compute.amazonaws.com
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;DEBIAN_FRONTEND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;noninteractive
hostname&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$EC2_HOSTNAME&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$EC2_HOSTNAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/hostname
aptitude&lt;span class="w"&gt; &lt;/span&gt;-y&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;puppetmaster
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/puppet/autosign.conf
service&lt;span class="w"&gt; &lt;/span&gt;puppetmaster&lt;span class="w"&gt; &lt;/span&gt;restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With the above, the only line you need to change is the value of the &lt;code&gt;EC2_HOSTNAME&lt;/code&gt; variable, which should be either the DNS name of the Elastic IP or the &lt;code&gt;CNAME&lt;/code&gt; record you created at your domain.&lt;/p&gt;
&lt;p&gt;The script will set the hostname of the instance, and then install Puppet master. The order of this is important, because when Puppet master is installed, it uses the hostname of the instance to create an SSL certificate for the master to use when auto signing agent certificates. If you have an incorrect hostname, the Puppet agents will complain and fail when trying to communicate with the master.&lt;/p&gt;
&lt;p&gt;We then also tell Puppet master to autosign all requests, and then restart the service for the changes to take affect.&lt;/p&gt;
&lt;p&gt;Now create the EC2 instance with the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-run-instances --user-data-file puppetmaster.sh -t t1.micro -g puppetmaster -k puppetmaster ami-3b65664f
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The instance will not be created, and started, and the user data script will run. In the output of this command, you&amp;rsquo;ll get details of the instance that has been created, along with an instance ID that starts with a prefix of &lt;code&gt;i-&lt;/code&gt;. Use that ID to associate the Elastic IP to the instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;associate&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;INSTANCEID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m m-Double"&gt;123.456.789.012&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Where &lt;code&gt;123.456.789.012&lt;/code&gt; is the Elastic IP address you was allocated earlier.&lt;/p&gt;
&lt;p&gt;Your master server is now setup and ready.&lt;/p&gt;
&lt;h2&gt;Setup your manifests&lt;/h2&gt;
&lt;p&gt;Although puppet master is ready to go, we don&amp;rsquo;t currently have any manifests setup. So for this example, we&amp;rsquo;ll just do a basic web server setup.&lt;/p&gt;
&lt;p&gt;SSH into the master:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;puppetmaster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="nv"&gt;@ec2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;456&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;789&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;012.&lt;/span&gt;&lt;span class="n"&gt;eu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;west&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="k"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amazonaws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Puppet master, by default, stores it&amp;rsquo;s manifests and modules at &lt;code&gt;/etc/puppet&lt;/code&gt;. We&amp;rsquo;ll create a simple manifest that installs &lt;code&gt;nginx&lt;/code&gt; and adds an &lt;code&gt;index.html&lt;/code&gt; file to the default virtual host.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/puppet/manifests/site.pp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the manifest file, add:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;package&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&amp;#39;nginx&amp;#39;:
&lt;span class="w"&gt;    &lt;/span&gt;ensure&lt;span class="w"&gt; &lt;/span&gt;=&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;present,
}

service&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&amp;#39;nginx&amp;#39;:
&lt;span class="w"&gt;    &lt;/span&gt;ensure&lt;span class="w"&gt;  &lt;/span&gt;=&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;running,
&lt;span class="w"&gt;    &lt;/span&gt;require&lt;span class="w"&gt; &lt;/span&gt;=&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Package[&amp;#39;nginx&amp;#39;],
}

file&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&amp;#39;/usr/share/nginx/www/index.html&amp;#39;:
&lt;span class="w"&gt;    &lt;/span&gt;content&lt;span class="w"&gt; &lt;/span&gt;=&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;#39;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;Puppet&lt;span class="w"&gt; &lt;/span&gt;master!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;&amp;#39;,
&lt;span class="w"&gt;    &lt;/span&gt;require&lt;span class="w"&gt; &lt;/span&gt;=&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Package[&amp;#39;nginx&amp;#39;],
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now when we boot up new Puppet agent instances, Puppet master will install &lt;code&gt;nginx&lt;/code&gt; on them, and update the default &lt;code&gt;index.html&lt;/code&gt; file with our changes.&lt;/p&gt;
&lt;h2&gt;The Puppet agents&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ve already created a security group for these instances, so we&amp;rsquo;ll just authorise SSH and HTTP traffic for it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-authorize -P tcp -p 22 puppets
ec2-authorize -P tcp -p 80 puppets
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create a keypair for the puppet agents to use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-create-keypair puppets | sed 1d &amp;gt; puppets.key
chmod 600 puppets.key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We need to create another user data script for the agents in order for them to install Puppet when they are first created. Create a file called &lt;code&gt;puppets.sh&lt;/code&gt; and put in it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;-x
&lt;span class="nv"&gt;EC2_HOSTNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ec2-123-456-789-012.eu-west-1.compute.amazonaws.com
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;DEBIAN_FRONTEND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;noninteractive
aptitude&lt;span class="w"&gt; &lt;/span&gt;-y&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;puppet
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;[agent]&lt;/span&gt;
&lt;span class="s2"&gt;server=&lt;/span&gt;&lt;span class="nv"&gt;$EC2_HOSTNAME&lt;/span&gt;
&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/puppet/puppet.conf
sed&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;/etc/default/puppet&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/START=no/START=yes/&amp;#39;&lt;/span&gt;
service&lt;span class="w"&gt; &lt;/span&gt;puppet&lt;span class="w"&gt; &lt;/span&gt;restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Again, you just need to update the &lt;code&gt;EC2_HOSTNAME&lt;/code&gt; variable to point to the DNS name (or custom &lt;code&gt;CNAME&lt;/code&gt;) pointing to the Elastic IP for the master server. The rest of the script installs Puppet, and points the Puppet agent to the master server. It also sets the Puppet agent to start when the instance is started or rebooted.&lt;/p&gt;
&lt;p&gt;Now you can create an instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-run-instances --user-data-file puppets.sh -t t1.micro -g puppets -k puppets ami-3b65664f
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Give the instance enough time to be created and booted. The following is then happening:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Puppet is being installed&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s being configured to use our puppet master&lt;/li&gt;
&lt;li&gt;The puppet agent requests to the puppet master, which accepts&lt;/li&gt;
&lt;li&gt;Puppet master sends over the manifests (and modules if you specify any) and starts executing them&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In our case, that means it&amp;rsquo;ll install &lt;code&gt;nginx&lt;/code&gt; and our test &lt;code&gt;index.html&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;So that we can check it has worked, run &lt;code&gt;ec2-describe-instances&lt;/code&gt; and in the output, find the instance that has the security group &lt;code&gt;puppets&lt;/code&gt;. That&amp;rsquo;ll be the one we just created. We want the public DNS name. Copy that, and paste it into a browser and you should see after a few minutes once it&amp;rsquo;s had time to setup:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hello from Puppet master!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Our Puppet agent has connected and hooked up to the master successfully. Now you can continue to create other agent instances knowing that they&amp;rsquo;ll connect up the same. Those instances can then all be managed by the Puppet master.&lt;/p&gt;
&lt;p&gt;Success.&lt;/p&gt;</content></entry><entry><title>Install EC2 command line tools with OS X</title><link href="https://davidwinter.dev/2012/12/07/install-ec2-command-line-tools-with-os-x/" rel="alternate"/><published>2012-12-07T00:00:00+00:00</published><updated>2012-12-07T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2012-12-07:/2012/12/07/install-ec2-command-line-tools-with-os-x/</id><summary type="html">&lt;p&gt;Be a ninja with EC2 using the CLI&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;ve been using EC2 a lot recently, probably creating and destroying around 20 instances trying out a project, today alone. I needed to be able to do this a lot faster than the web console lets me, so I downloaded the EC2 command line tools to give me that bit extra.&lt;/p&gt;
&lt;h2&gt;Installing&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s very easy to setup:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Grab the zip file from the &lt;a href="http://aws.amazon.com/developertools/351"&gt;AWS developer site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unzip to your home directory&lt;/li&gt;
&lt;li&gt;Rename the extracted directory to &lt;code&gt;.ec2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Go to the &lt;a href="https://portal.aws.amazon.com/gp/aws/developer/account/index.html?action=access-key"&gt;Security Credentials&lt;/a&gt; page on the AWS site&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;X.509 Certificates&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create a new Certificate&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Download the two files in the popup to your &lt;code&gt;~/.ec2&lt;/code&gt; directory&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Configuring to work with your CLI&lt;/h2&gt;
&lt;p&gt;Now we need to configure our shell&amp;ndash;&lt;a href="http://ridiculousfish.com/shell/"&gt;Fish&lt;/a&gt; in my case&amp;ndash;to use the EC2 tools. Copy the following into your &lt;code&gt;~/.config/fish/config.fish&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;set PATH $EC2_HOME/bin $PATH
set -g -x JAVA_HOME /System/Library/Frameworks/JavaVM.framework/Home/
set -g -x EC2_HOME ~/.ec2
set -g -x EC2_URL https://eu-west-1.ec2.amazonaws.com
set -g -x EC2_PRIVATE_KEY (ls {$EC2_HOME}/pk-*.pem)
set -g -x EC2_CERT (ls {$EC2_HOME}/cert-*.pem)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you&amp;rsquo;re using &lt;code&gt;bash&lt;/code&gt; or &lt;code&gt;zsh&lt;/code&gt;, it&amp;rsquo;s a similar setup - just create the variables, and update your &lt;code&gt;PATH&lt;/code&gt;. Here&amp;rsquo;s &lt;code&gt;bash&lt;/code&gt; (add this to your &lt;code&gt;~/.bash_profile&lt;/code&gt; file):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=$&lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;EC2_HOME&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;JAVA_HOME&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Library&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Frameworks&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;JavaVM&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EC2_HOME&lt;/span&gt;&lt;span class="o"&gt;=~/.&lt;/span&gt;&lt;span class="n"&gt;ec2&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EC2_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;eu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;west&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amazonaws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EC2_PRIVATE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;EC2_HOME&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;-*.&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EC2_CERT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;EC2_HOME&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="o"&gt;-*.&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I&amp;rsquo;ve set my default region to &lt;code&gt;eu-west-1&lt;/code&gt;. You may want to set this to something different. Change the &lt;code&gt;EC2_URL&lt;/code&gt; variable accordingly.&lt;/p&gt;
&lt;p&gt;Open a new tab or terminal window and the changes should now be present. To check, you can run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-describe-instances
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should get a list of the instances currently associated to your account in your default region.&lt;/p&gt;
&lt;h2&gt;Taking the tools for a spin&lt;/h2&gt;
&lt;p&gt;A good way to test the tools is to use my previous post on &lt;a href="/2012/12/06/getting-started-with-amazon-ec2"&gt;getting started with EC2&lt;/a&gt;, but rather than using the web AWS console, we&amp;rsquo;ll use nothing but the command line tools.&lt;/p&gt;
&lt;p&gt;Create the key pair:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-create-keypair blog | sed 1d &amp;gt; blog.key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The output of this file includes a fingerprint of the key at the top, which we don&amp;rsquo;t want, so we use &lt;code&gt;sed&lt;/code&gt; to remove that line so we can easily save it to a file. We then just set restrictive permissions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;chmod 600 blog.key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create the security group:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-create-group blog -d Blog
ec2-authorize blog -P tcp -p 22
ec2-authorize blog -P tcp -p 80
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create and run the instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ec2-run-instances -t t1.micro -g blog -k blog ami-e9eded9d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;From the output of this command, get the instance ID, which is prefixed with &lt;code&gt;i-&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Assign a dedicated IP:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;allocate&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above command will output an IP address. Copy that to your clipboard, and use it in the following command (paste it in place of &lt;code&gt;123.456.789.012&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;associate&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;INSTANCE_ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m m-Double"&gt;123.456.789.012&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can then ssh into the instance with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="mf"&gt;@123.456.789.012&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All done.&lt;/p&gt;</content></entry><entry><title>Getting started with Amazon EC2</title><link href="https://davidwinter.dev/2012/12/06/getting-started-with-amazon-ec2/" rel="alternate"/><published>2012-12-06T00:00:00+00:00</published><updated>2012-12-06T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2012-12-06:/2012/12/06/getting-started-with-amazon-ec2/</id><summary type="html">&lt;p&gt;It&amp;rsquo;s not as difficult as it may first seem&lt;/p&gt;</summary><content type="html">&lt;p&gt;A few friends have asked me to talk through how to setup an Amazon EC2 server.&lt;/p&gt;
&lt;p&gt;At first glance, it&amp;rsquo;s very intimidating, confusing, and not quite clear where to start. But once you know about all the pieces that bring together the AWS services, it&amp;rsquo;s not difficult at all to get a server up and running.&lt;/p&gt;
&lt;p&gt;The great thing about EC2 is that the servers are virtualised. That means you can create and throw them away when not needed very easily. This makes it great for testing out things, not having to worry that you&amp;rsquo;ll have to pay out for a full server for a month. Boot up an EC2 server, run it for a few minutes, or non-stop. It&amp;rsquo;s up to you. You have complete freedom and flexibility.&lt;/p&gt;
&lt;p&gt;Ready to tuck in?&lt;/p&gt;
&lt;h2&gt;Some definitions&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll start off with defining some of the core pieces that you&amp;rsquo;ll need to be able to create, and then run an EC2 server:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;EC2&lt;/em&gt; &amp;amp; &lt;em&gt;Instances&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;EC2 stands for Elastic Cloud Compute. This service allows you to setup virtual machines (known as instances) to run an operating system of your choice (mine is Ubuntu).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;EBS&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Elastic Block Store, these are the virtual hard drives your instance will use.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;AMI&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Amazon Machine Image, these are best described as base installs of an operating system, with a default configuration set and ready for the EC2 service.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Security Groups&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is where you can setup what is essentially a firewall for your instance. You say what ports are open on it. This means in the majority of cases you don&amp;rsquo;t need to setup a software firewall on your install (such as &lt;code&gt;iptables&lt;/code&gt; or &lt;code&gt;ufw&lt;/code&gt;). It saves a lot of headaches.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Key Pairs&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are the SSH keys that you&amp;rsquo;ll use to connect to your instance. When you create the machine, the public key of the selected pair is already added to the &lt;code&gt;authorized_keys&lt;/code&gt; file, and you then download and use a private key to connect.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Elastic IPs&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Allows you to assign a dedicated IP to the instance. Not required, but helpful for when ready to launch, and want to point a domain name.&lt;/p&gt;
&lt;h2&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Before you can do anything, you need to have an AWS account. Register if you don&amp;rsquo;t already have one, then head to the &lt;a href="https://console.aws.amazon.com/console/home"&gt;AWS Console&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve already mentioned that Ubuntu is my OS of choice, so we need an AMI to base our instance on. I always use the official Cannonical (who manage Ubuntu) ones, and they have a &lt;a href="http://cloud-images.ubuntu.com/locator/ec2/"&gt;helpful webpage&lt;/a&gt; for you to find the correct AMI-ID. You need this ID in order to tell EC2 which AMI to use.&lt;/p&gt;
&lt;p&gt;I want to use the latest version of Ubuntu (12.10 at time of writing), with a 64 bit processor, based in the EU region (which is in Ireland) with an EBS hard drive.&lt;/p&gt;
&lt;p&gt;To narrow down the list of available AMI&amp;rsquo;s, I type in &amp;lsquo;12.10 amd64 eu ebs&amp;rsquo; into the &lt;a href="http://cloud-images.ubuntu.com/locator/ec2/"&gt;search box&lt;/a&gt;. We&amp;rsquo;re then left with one AMI - &lt;code&gt;ami-e9eded9d&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Creating the instance&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll notice that the ID is a link which you can click on to start creating your EC2 instance. It directs you onto the AWS console.&lt;/p&gt;
&lt;p&gt;The first screen gives you a summary of the AMI and the defaults for the hard drive setup - which is 8GB. This can be increased at a later time if needed. Click &amp;lsquo;Continue&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;The important part on this step is selecting the size of the instance. It should be defaulted to &amp;lsquo;T1 Micro&amp;rsquo;. Amazon &lt;a href="http://aws.amazon.com/ec2/instance-types/"&gt;offer a variety of sizes&lt;/a&gt; that increase the power and RAM for your instance. The bigger the instance, the more you pay. Again, these can be changed at a later point. Ensure &amp;lsquo;T1 Micro&amp;rsquo; is selected and then continue.&lt;/p&gt;
&lt;p&gt;We won&amp;rsquo;t be choosing any advanced options, so skip the next step. We&amp;rsquo;ll also leave the default hard drive configuration, so skip the following step too.&lt;/p&gt;
&lt;p&gt;The next screen allows you to name the instance. You&amp;rsquo;ll see a key with the name prefilled &amp;lsquo;Name&amp;rsquo;, and you can set the value to something descriptive. If you&amp;rsquo;re running a blog on the instance perhaps call it &amp;lsquo;blog&amp;rsquo;. Click &amp;lsquo;Continue&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;When the instance is running, you&amp;rsquo;ll need to be able to connect to it via SSH so you can configure it. This is where SSH key pairs come into play. You&amp;rsquo;ll want to create a new key pair. You just need to give it a name, and then click on the &amp;lsquo;Create &amp;amp; Download your Key Pair&amp;rsquo;. Depending on what you call the Key Pair, for example, &amp;lsquo;blog&amp;rsquo;, a file called &lt;code&gt;blog.pem&lt;/code&gt; will download. Keep this somewhere safe and secure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It&amp;rsquo;d be a good idea to add a passphrase to this key file so that if someone did get the key, they couldn&amp;rsquo;t use it to connect to your server without the passphrase. For this demonstration, we&amp;rsquo;ll leave it as is, without. There&amp;rsquo;s a good writeup on &lt;a href="https://help.github.com/articles/working-with-ssh-key-passphrases"&gt;Github&lt;/a&gt; on why and how to use and create them.&lt;/p&gt;
&lt;p&gt;Next we need to configure the Security Group for the instance. Create a new one and give it a name and description. Then you can either choose from the dropdown for common port configurations, or set something custom. We&amp;rsquo;ll enable SSH (so we can connect to it remotely) and HTTP (because we&amp;rsquo;ll probably be running a web server) for this instance. Select both of these, and add them to the Security Group. Click &amp;lsquo;Continue&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re now on the final step before creating and starting the instance. You can check all of the configuration options we&amp;rsquo;ve set from here, and then you&amp;rsquo;re ready to launch. Click &amp;lsquo;Launch&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;AWS will tell you that your instance is now launching. Click on &amp;lsquo;Close&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;In the left hand menu of the console, select &amp;lsquo;Instances&amp;rsquo;. You should see a &amp;lsquo;running&amp;rsquo; status for the instance you just created it. Select it from the list.&lt;/p&gt;
&lt;p&gt;In the details section of the page near the bottom, you&amp;rsquo;ll see your instance has been selected, and it will give you a hostname you can use to connect to your instance with. It&amp;rsquo;ll look something like &lt;code&gt;ec2-12-345-67-890.eu-west-1.compute.amazonaws.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before we connect, you need to give the private key you downloaded earlier strict, private permissions for your user only.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;chmod 600 path/to/blog.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you can connect to your instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;path&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;blog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="nv"&gt;@ec2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;345&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;890.&lt;/span&gt;&lt;span class="n"&gt;eu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;west&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="k"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amazonaws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll notice the user I&amp;rsquo;m connecting with is called &lt;code&gt;ubuntu&lt;/code&gt;. This is the default user that the AMI we&amp;rsquo;re using has setup. You should be promted to add the host to your known hosts file, so type in &lt;code&gt;yes&lt;/code&gt; and hit enter.&lt;/p&gt;
&lt;p&gt;And then, you&amp;rsquo;re in! Connected to your brand new instance, with a fresh install of Ubuntu 12.10 on it.&lt;/p&gt;
&lt;h2&gt;Give your instance a dedicated IP&lt;/h2&gt;
&lt;p&gt;You can now logout from SSH, and then we&amp;rsquo;ll assign a dedicated IP to the instance, which you&amp;rsquo;d then be able to use to point a DNS A record to the instance.&lt;/p&gt;
&lt;p&gt;In your AWS console, select Elastic IPs. Select &amp;lsquo;Allocate New Address&amp;rsquo; and EC2 should be selected in the dropdown. Click &amp;lsquo;Yes, Allocate&amp;rsquo;. With the new IP selected, click on &amp;lsquo;Associate Address&amp;rsquo;, choose the instance you&amp;rsquo;ve just created and then click on &amp;lsquo;Yes, Associate&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;Copy that new IP address to your clipboard, and then you can connect to your instance again with that:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;blog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="mf"&gt;@123.456.789.012&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example, we&amp;rsquo;re using &lt;code&gt;123.456.789.012&lt;/code&gt; as that newly created IP. You should get the known hosts prompt again, type &lt;code&gt;yes&lt;/code&gt;, and then you&amp;rsquo;ll be connected again.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it. You&amp;rsquo;re ready to go.&lt;/p&gt;
&lt;h2&gt;Aditional notes&lt;/h2&gt;
&lt;p&gt;You pay for what you use on AWS. And the pricing is a bit complicated because of the level of detail at which Amazon charge you for. Processing time, bandwidth used, disk space consumed, IP addresses, etc etc.&lt;/p&gt;
&lt;p&gt;A handy calculator is available to work out how much you&amp;rsquo;re likely to pay: &lt;a href=""&gt;http://calculator.s3.amazonaws.com/calc5.html&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While you&amp;rsquo;re developing with AWS, it&amp;rsquo;s probably a good idea to turn off your instance while you&amp;rsquo;re not using it. You can do this from the console by right clicking on the instance and clicking on &amp;lsquo;Stop&amp;rsquo;. To boot it up again, do the same but select &amp;lsquo;Start&amp;rsquo; instead. If you want to delete the instance because you won&amp;rsquo;t be using it again, select &amp;lsquo;Terminate&amp;rsquo;. That&amp;rsquo;ll delete the data on the instance, so terminate carefully.&lt;/p&gt;</content></entry><entry><title>Install and manage WordPress with Git</title><link href="https://davidwinter.dev/2012/04/09/install-and-manage-wordpress-with-git/" rel="alternate"/><published>2012-04-09T00:00:00+01:00</published><updated>2012-04-09T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2012-04-09:/2012/04/09/install-and-manage-wordpress-with-git/</id><summary type="html">&lt;p&gt;Keeping the core separate, but easy to update&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;ve been a massive fan of the &amp;lsquo;&lt;a href="http://codex.wordpress.org/Installing/Updating_WordPress_with_Subversion"&gt;Installing/Updating Wordpress with Subversion&lt;/a&gt;&amp;rsquo; instructions on the WordPress codex for a good few years. If you have ssh access to a server and are managing a couple of WordPress sites, keeping them up-to-date with the latest version is easy with just one svn command.&lt;/p&gt;
&lt;p&gt;However, with a bigger WordPress project in the pipeline, I need to be able to manage my themes and plugins in a git repository, while at the same time keep a reference to the core WordPress files, and allow it to be as easy to update when a new version is released.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not going to continue with the SVN instructions because that&amp;rsquo;d add a lot of mess to my git repository - including SVN history. I want to keep track of my changes only - none of the WordPress related ones.&lt;/p&gt;
&lt;p&gt;The good news is, this is all possible. It takes a few minutes longer to setup, but once done, updating will be as easy. You&amp;rsquo;ll also have a really tidy git repo.&lt;/p&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: You can view the finished project on Github; &lt;a href="https://github.com/davidwinter/wordpress-with-git"&gt;davidwinter/wordpress-with-git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Create a new project directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir mysite &amp;amp;&amp;amp; cd mysite
git init
touch README.md
git add README.md
git commit -m &amp;quot;Initial commit.&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You now have a blank project to start with.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll be using the &lt;a href="https://github.com/WordPress/WordPress"&gt;Github WordPress&lt;/a&gt; mirror that is synced with the official SVN repository every 30 minutes. It includes all tags and branches.&lt;/p&gt;
&lt;p&gt;We want to add this as a subrepository to our main project.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git submodule add git://github.com/WordPress/WordPress.git wordpress
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;WordPress is quite a big project if you haven&amp;rsquo;t already noticed, so it might take a while to make a clone. Once done, commit the new subrepository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git commit -m &amp;quot;Add WordPress subrepository.&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We want to ensure our project is using the current stable version. As of writing, this is 3.3.1.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd wordpress
git checkout 3.3.1
cd ..
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This has now updated the WordPress repository to 3.3.1 - commit the changes to your main project.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git commit -am &amp;quot;Checkout WordPress 3.3.1&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The subrepository is now isolated, and we don&amp;rsquo;t want to make any changes to it, besides bumping version numbers. This means we can&amp;rsquo;t modify wp-config.php, themes or plugins. We&amp;rsquo;ll have to move things about a bit.&lt;/p&gt;
&lt;p&gt;First up, we&amp;rsquo;ll create our config file. WordPress allows for this to be stored one directory up from the core WordPress files.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cp wordpress/wp-config-sample.php wp-config.php
git add wp-config.php
git commit -m &amp;quot;Adding default wp-config.php file&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now that this is outside of the WordPress repository, we&amp;rsquo;ll be able to configure WordPress and commit the changes to our main project repository.&lt;/p&gt;
&lt;p&gt;Now, in order to manage themes and plugins we need to make a copy of the &lt;code&gt;wp-content&lt;/code&gt; directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cp -R wordpress/wp-content .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will copy the directory and its contents into our main project repo.&lt;/p&gt;
&lt;p&gt;Now, at this point you may like to tidy up that directory a little. This isn&amp;rsquo;t required, but will save you commiting themes and plugins you&amp;rsquo;ll probably never use.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;rm wp-content/plugins/hello.php
rm -rf wp-content/themes/twentyten
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you plan on using the default WordPress theme, Twenty Eleven, don&amp;rsquo;t run the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;rm -rf wp-content/themes/twentyeleven
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now commit this directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git add wp-content
git commit -m &amp;quot;Adding default wp-content directory&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We now have a trimed down &lt;code&gt;wp-content&lt;/code&gt; directory ready for only &lt;em&gt;our&lt;/em&gt; themes and plugins.&lt;/p&gt;
&lt;p&gt;To finish off the project structure, we need to copy the WordPress &lt;code&gt;index.php&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cp wordpress/index.php .
git add index.php
git commit -m &amp;quot;Adding index.php&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we need to configure these files and let WordPress know where to talk to everything.&lt;/p&gt;
&lt;h2&gt;Configuring&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll start with &lt;code&gt;index.php&lt;/code&gt;. This is the file all requests go via, and we just need to update a &lt;code&gt;require&lt;/code&gt; statement. Find the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;require(&amp;#39;./wp-blog-header.php&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And update it to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;require(&amp;#39;./wordpress/wp-blog-header.php&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Commit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git commit -am &amp;quot;Pointing index.php to the correct location&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now into &lt;code&gt;wp-config.php&lt;/code&gt;, open it up. Because we have the core WordPress files in a different directory to that of the &lt;code&gt;index.php&lt;/code&gt; file, we need to let WordPress know about it. Add the following two constants to the file. I prefer just below the &lt;code&gt;@package WordPress&lt;/code&gt; statement so my changes are near the top of the file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WordPress&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*/&lt;/span&gt;

&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;WP_SITEURL&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//&amp;#39; . $_SERVER[&amp;#39;SERVER_NAME&amp;#39;] . &amp;#39;/wordpress&amp;#39;);&lt;/span&gt;
&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;WP_HOME&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//&amp;#39; . $_SERVER[&amp;#39;SERVER_NAME&amp;#39;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This lets WordPress know that the core files are in the &lt;code&gt;wordpress&lt;/code&gt; directory, but that the site is to be served at the root of the project directory.&lt;/p&gt;
&lt;p&gt;Because we moved the &lt;code&gt;wp-content&lt;/code&gt; directory out of the core WordPress directory, we also have to let it know about this change. Add the following after the previous define statements:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;define&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WP_CONTENT_DIR&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;_SERVER&lt;/span&gt;&lt;span class="cp"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DOCUMENT_ROOT&amp;#39;&lt;/span&gt;&lt;span class="cp"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/wp-content&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;define&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WP_CONTENT_URL&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;_SERVER&lt;/span&gt;&lt;span class="cp"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SERVER_NAME&amp;#39;&lt;/span&gt;&lt;span class="cp"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/wp-content&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And finally, if you&amp;rsquo;re not using the default &lt;code&gt;twentyeleven&lt;/code&gt; theme, and want to specify the one WordPress should use instead:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;define(&amp;#39;WP_DEFAULT_THEME&amp;#39;, &amp;#39;mytheme&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Simply replace &lt;code&gt;mytheme&lt;/code&gt; with the name of the theme you have. Be sure that you&amp;rsquo;ve placed it inside the &lt;code&gt;wp-content/themes&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Now simply complete the database details as normal further down in the file, and then visit the project on your webhost and you&amp;rsquo;ll be up and running.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git commit -am &amp;quot;Update settings in wp-config.php&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Updating&lt;/h2&gt;
&lt;p&gt;Change into the WordPress subrepository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd wordpress
git fetch --tags
git checkout 3.3.2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Replace 3.3.2 with the correct version number.&lt;/p&gt;
&lt;p&gt;Now commit the changes subrepository version to your main project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ..
git commit -m &amp;quot;Update WordPress to version 3.3.2&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Helpful references&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://codex.wordpress.org/Hardening_WordPress#Securing_wp-config.php"&gt;Moving wp-config.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://codex.wordpress.org/Changing_The_Site_URL"&gt;Changing the WordPress directory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://codex.wordpress.org/Editing_wp-config.php#Moving_wp-content"&gt;Moving wp-content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://codex.wordpress.org/Network_Admin_Themes_Screen#Default_Theme"&gt;Setting default theme constant&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content></entry><entry><title>Introduction to Puppet</title><link href="https://davidwinter.dev/2012/03/04/introduction-to-puppet/" rel="alternate"/><published>2012-03-04T00:00:00+00:00</published><updated>2012-03-04T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2012-03-04:/2012/03/04/introduction-to-puppet/</id><summary type="html">&lt;p&gt;Puppet can change your life&lt;/p&gt;</summary><content type="html">&lt;p&gt;Have you ever had that déjà vu feeling when setting up a new server? That you&amp;rsquo;ve done it all before, and that it&amp;rsquo;s really tedious to have to do it all over again? You&amp;rsquo;d rather be able to just hit a button to deploy your app and start showing it off to the world.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s exactly what happened to me, and at first I thought I&amp;rsquo;d just write a bash script with all the various steps that I had started noting down in a plain text file. Luckily, at the point I was considering this, I saw the release of a new project called &lt;a href="http://vagrantup.com/"&gt;Vagrant&lt;/a&gt;. It&amp;rsquo;s a tool that allows you to run a virtual machine locally, with a helpful shared directory to your files on your local (host) machine. It allows you to setup a self contained development environment without messing around with your system.&lt;/p&gt;
&lt;p&gt;Reading through the &lt;a href="http://vagrantup.com/docs/index.html"&gt;documentation&lt;/a&gt;, I saw it mention &lt;a href="http://puppetlabs.com/"&gt;Puppet&lt;/a&gt; and &lt;a href="http://www.opscode.com/chef/"&gt;Chef&lt;/a&gt; which both appeared to be some sort of witchcraft that allowed you to automatically configure and setup these virtualised servers. Bingo. Easy server configuration management.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t have to use Vagrant to use Puppet. It&amp;rsquo;s just a really easy way to test it out locally. For your production environments you&amp;rsquo;ll still use the same puppet manifests, but you&amp;rsquo;ll manage the running of those manifests a &lt;a href="http://docs.puppetlabs.com/#part-two-masteragent-puppet"&gt;little different&lt;/a&gt;. I&amp;rsquo;ll be covering the Vagrant approach for this blog post.&lt;/p&gt;
&lt;p&gt;What do I want to demonstrate? Just a quick demo of how to get Puppet to install &lt;a href="http://wiki.nginx.org/Main"&gt;Nginx&lt;/a&gt; and &lt;a href="http://uk.php.net/manual/en/install.fpm.php"&gt;php-fpm&lt;/a&gt; on a server, serving a simple &lt;code&gt;phpinfo()&lt;/code&gt; file. It should be enough to make you thirtsy for more.&lt;/p&gt;
&lt;h2&gt;Some quick steps for setup&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll need to have &lt;a href="https://www.virtualbox.org/"&gt;Virtual Box&lt;/a&gt; installed with the command line tools option. Then install the Vagrant gem on your computer with a simple&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gem install vagrant
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now create a new directory on your machine where you&amp;rsquo;re going to work on this project.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir testing-vagrant
cd testing-vagrant/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All Vagrant projects use a &amp;lsquo;box&amp;rsquo; as a starting point for your project. It&amp;rsquo;s an virtual disk image of an OS installation that has all the dependencies to interact with Vagrant, and to run puppet manifests. Now, the one on the Vagrant website is Ubuntu 10.04 Lucid Lynx, and without some tinkering, it&amp;rsquo;s not as easy to get the latest versions of packages. So instead, I created my own Vagrant box for Ubuntu 11.10 Oneiric Ocelot using the open source tool &lt;a href="https://github.com/jedi4ever/veewee"&gt;VeeWee&lt;/a&gt;. It&amp;rsquo;s hosted on my public &lt;a href="http://db.tt/AamRjYgb"&gt;Dropbox&lt;/a&gt; folder, and to add this box to your vagrant setup, run the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;vagrant box add oneiric32 http://dl.dropbox.com/u/11342885/oneiric32.box
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once this has been downloaded, you need to initialise your Vagrant project with this box:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;vagrant init oneiric32
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create a file named &lt;code&gt;Vagrantfile&lt;/code&gt; in your project directory. This file has a bunch of different configuration options commented out. It&amp;rsquo;s a really helpful file to read through.&lt;/p&gt;
&lt;p&gt;One configuration option you&amp;rsquo;ll need to set is the port forwarding of the webserver. Ensure this line is present:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;config.vm.forward_port 80, 8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will forward on the port &lt;code&gt;8080&lt;/code&gt; of your local machine to port &lt;code&gt;80&lt;/code&gt; on the vagrant virtualbox. If you don&amp;rsquo;t have any other webservers running on your local machine, feel free to point this to port &lt;code&gt;80&lt;/code&gt; directly.&lt;/p&gt;
&lt;p&gt;Also, ensure these lines are present too:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;config.vm.provision :puppet, :module_path =&amp;gt; &amp;quot;private/puppet/modules&amp;quot; do |puppet|
  puppet.manifests_path = &amp;quot;private/puppet/manifests&amp;quot;
  puppet.manifest_file  = &amp;quot;base.pp&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the Puppet configuration. It tells Vagrant where the modules and manifests directories are, and the base manifest file.&lt;/p&gt;
&lt;p&gt;And finally, create these directories in your project for storing the different Puppet configuration files we need:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir -p private/puppet/{manifests,modules/nginx/files}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Playing with Puppet&lt;/h2&gt;
&lt;p&gt;To understand how to use Puppet, you need to think of a Puppet manifest as a file that defines the different resources your server requires. Resources in Puppet speak are things like users, groups, packages, commands, services and files&amp;ndash;to name a few. We define these resources in a manifests file which you&amp;rsquo;ll place in &lt;code&gt;private/puppet/manifests/base.pp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now the first thing we want to do with the base box is ensure that everything is up-to-date. The first resource we&amp;rsquo;ll define is an executable command to run. Basically an &lt;code&gt;apt-get update&lt;/code&gt;. In your &lt;code&gt;base.pp&lt;/code&gt; file add the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;apt-get update&amp;#39;&lt;/span&gt;:
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/usr/bin/apt-get update&amp;#39;&lt;/span&gt;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All resources follow this same structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;resource_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;title&lt;/code&gt; is quite an important value, as it is often used as a default option value too. For example, with the &lt;code&gt;user&lt;/code&gt; resource, the title you specify will be the name of the user to create. This can be overriden if you need to define a descriptive title that isn&amp;rsquo;t the name of the user you want to create. For the &lt;code&gt;user&lt;/code&gt; resource, you&amp;rsquo;d override this with the &lt;code&gt;name&lt;/code&gt; option. For example, the following would both create the same user:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;david&amp;#39;&lt;/span&gt;:
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;ensure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;present&lt;/span&gt;,
}

&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;my descriptive title for my username&amp;#39;&lt;/span&gt;:
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;david&amp;#39;&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;ensure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;present&lt;/span&gt;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note: Due to an issue with VeeWee not creating a required user group on the Oneiric box, you need to also tell Puppet to create the &lt;code&gt;puppet&lt;/code&gt; group. This can be done with the following. Not doing this will result in errors:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;group { &amp;#39;puppet&amp;#39;:
    ensure =&amp;gt; present,
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Back to our example. We now have a command resource that will run &lt;code&gt;apt-get update&lt;/code&gt;. Once this has been run, we want to install the packages &lt;code&gt;nginx&lt;/code&gt; and &lt;code&gt;php-fpm&lt;/code&gt;. We want to ensure though that &lt;code&gt;apt-get update&lt;/code&gt; has run beforehand. Now, with Puppet, it&amp;rsquo;s important to note that the manifest files are not run through sequentially as you might expect. Each time they are run, they can happen in a different order. You need to explicity set dependencies and requirements.&lt;/p&gt;
&lt;p&gt;To install the &lt;code&gt;nginx&lt;/code&gt; package, we&amp;rsquo;ll add the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;nginx&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ensure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;present&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A few things to note here. The package to install is being derived from the resource title. It defaults to this, or you can specify the option with the option key &lt;code&gt;name&lt;/code&gt;. We tell puppet to ensure that it&amp;rsquo;s present on the system. We also say that this resource requires that the executable command &lt;code&gt;apt-get update&lt;/code&gt; has already been applied.&lt;/p&gt;
&lt;p&gt;When you reference other resources in a manifest file, the resource type has the first letter capitalised. Then you specify the title of the resource you&amp;rsquo;re referencing. This is where resource titles are used.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll also do the same for the &lt;code&gt;php-fpm&lt;/code&gt; package:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;php5&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;fpm&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ensure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;present&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Each of these packages come with a service that runs in the background, that we want to ensure is running all the time. We can make Puppet check this is the case with the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;service { &amp;#39;nginx&amp;#39;:
    ensure =&amp;gt; running,
    require =&amp;gt; Package[&amp;#39;nginx&amp;#39;],
}

service { &amp;#39;php5-fpm&amp;#39;:
    ensure =&amp;gt; running,
    require =&amp;gt; Package[&amp;#39;php5-fpm&amp;#39;],
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice the require dependencies? Whenever Puppet runs it will check that these are running, and if they&amp;rsquo;re not, for whatever reason, it will start them.&lt;/p&gt;
&lt;p&gt;Ready to see some magic? Save the file and run &lt;code&gt;vagrant up&lt;/code&gt;. Vagrant will boot up the virtual machine, and run the Puppet manifest on it. Once it&amp;rsquo;s finished visit &lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt; and you should see:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Welcome to nginx!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You&amp;rsquo;ve not had to ssh into the machine once or run anything on the command line of that VM.&lt;/p&gt;
&lt;p&gt;Now in order to get PHP setup and running with nginx, we need to modify some of the nginx config files. We need to do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Disable the default nginx virtual host.&lt;/li&gt;
&lt;li&gt;Copy over a new virtual host for our vagrant setup that forwards on PHP requests to &lt;code&gt;php-fpm&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Symbolically link the virtual host config file to the sites-enabled directory.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the &lt;code&gt;private/puppet/modules/nginx/files&lt;/code&gt; directory we created, add the following in a file called &lt;code&gt;vagrant&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/vagrant&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;try_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$uri&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;php&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;fastcgi_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;127.0.0.1:9000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;fastcgi_index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;fastcgi_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a standard nginx configuration file for a virtual host. It will use &lt;code&gt;/vagrant&lt;/code&gt; on the virtual machine as the document root. This is a shared directory that Vagrant sets up to link to your project directory on your local machine.&lt;/p&gt;
&lt;p&gt;Saving that file, we can now open up the &lt;code&gt;base.pp&lt;/code&gt; file again and add a few more resources. The first is to copy over this virtual host to the correct location:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;file { &amp;#39;vagrant-nginx&amp;#39;:
    path =&amp;gt; &amp;#39;/etc/nginx/sites-available/vagrant&amp;#39;,
    ensure =&amp;gt; file,
    require =&amp;gt; Package[&amp;#39;nginx&amp;#39;],
    source =&amp;gt; &amp;#39;puppet:///modules/nginx/vagrant&amp;#39;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now lets disable the default virtual host the nginx package provides:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;file { &amp;#39;default-nginx-disable&amp;#39;:
    path =&amp;gt; &amp;#39;/etc/nginx/sites-enabled/default&amp;#39;,
    ensure =&amp;gt; absent,
    require =&amp;gt; Package[&amp;#39;nginx&amp;#39;],
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And finally, enable our new vagrant virtual host:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;file { &amp;#39;vagrant-nginx-enable&amp;#39;:
    path =&amp;gt; &amp;#39;/etc/nginx/sites-enabled/vagrant&amp;#39;,
    target =&amp;gt; &amp;#39;/etc/nginx/sites-available/vagrant&amp;#39;,
    ensure =&amp;gt; link,
    notify =&amp;gt; Service[&amp;#39;nginx&amp;#39;],
    require =&amp;gt; [
        File[&amp;#39;vagrant-nginx&amp;#39;],
        File[&amp;#39;default-nginx-disable&amp;#39;],
    ],
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file and run &lt;code&gt;vagrant reload&lt;/code&gt;. This tells vagrant to run the puppet provisioner again and ensure that the virtual machine matches the resources specified in the manifests file. We&amp;rsquo;ve just added three new ones, so it will action these.&lt;/p&gt;
&lt;p&gt;Ready to test it has all worked as expected? Create an &lt;code&gt;index.php&lt;/code&gt; file in your project directory, the same location where your &lt;code&gt;Vagrantfile&lt;/code&gt; is. In there just put a simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="nb"&gt;phpinfo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file. Visit &lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt; again and you should see the standard &lt;code&gt;phpinfo&lt;/code&gt; page being served over php-fpm via nginx.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it for this introduction. Hopefully it&amp;rsquo;s enough to get you excited. For me, it means being able to keep a manifest file up-to-date, and if I ever change my VPS to a different provider and want to get it up and running within a few minutes rather than hours, I can apply it with Puppet. No more keeping a log of the many steps I would have to manually run over ssh as the alternative.&lt;/p&gt;
&lt;p&gt;If you want to know more, here are some great resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://docs.puppetlabs.com/puppet_core_types_cheatsheet.pdf"&gt;Puppet cheatsheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.puppetlabs.com/#part-one-serverless-puppet"&gt;Official puppet documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://vagrantup.com/docs/index.html"&gt;Vagrant documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/davidwinter/Puppet-nginx-php-fpm-example"&gt;Github repo of this example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content></entry><entry><title>Testing Javascript websites with Behat</title><link href="https://davidwinter.dev/2012/01/14/testing-javascript-websites-with-behat/" rel="alternate"/><published>2012-01-14T00:00:00+00:00</published><updated>2012-01-14T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2012-01-14:/2012/01/14/testing-javascript-websites-with-behat/</id><summary type="html">&lt;p&gt;Using the Behat WebDriver driver to easily test websites with Javascript&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;This is my third blog post on how to use Behat for your web application testing. If you haven&amp;rsquo;t already, be sure to read &lt;a href="/2011/11/06/getting-started-with-behat/"&gt;Getting started with Behat&lt;/a&gt; and &lt;a href="/2012/01/13/using-behat-with-mink/"&gt;Using Behat with Mink&lt;/a&gt; as this post continues on where they left off.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In my previous post I left you with being able to create your own custom, reusable definitions in Behat. We&amp;rsquo;ve touched on the real basics of testing with Behat on a very simple example website. However, in 2012, you&amp;rsquo;ll find it very hard to find a website that doesn&amp;rsquo;t have some kind of Javascript included providing a dynamic and better user experience for visitors. It&amp;rsquo;s crucial that we&amp;rsquo;re able to test and guarantee that the animations and ajax requests that the users interact with work as we expect.&lt;/p&gt;
&lt;p&gt;In this blog post, we&amp;rsquo;ll be using the &lt;a href="http://twitter.github.com/bootstrap/javascript.html"&gt;twitter bootstrap example&lt;/a&gt; site. It has a variety of different JS related widgets and interactions which are perfect for explaining some of the basic Javascript testing concepts when it comes to Behat. Here is the &lt;code&gt;behat.yml&lt;/code&gt; configuration file being used:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;://&lt;/span&gt;&lt;span class="n"&gt;twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;com&lt;/span&gt;&lt;span class="sr"&gt;/bootstrap/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now take a look at the following example test:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Modal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dialog&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dialog&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/javascript.html&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Launch Modal&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;press&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Launch Modal&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;One fine body…&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you visit the &lt;a href="http://twitter.github.com/bootstrap/javascript.html#modal"&gt;modals section&lt;/a&gt; on the example site, there is a red button under the demo heading. Clicking that opens a modal box with the text &amp;lsquo;One fine body…&amp;rsquo;. That&amp;rsquo;s what our above test is for. Run that test and you&amp;rsquo;ll probably see:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Modal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dialog&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dialog&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;features&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;feature&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/javascript.html&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FeatureContext&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Launch Modal&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FeatureContext&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;assertPageContainsText&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;press&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Launch Modal&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FeatureContext&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;pressButton&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;selected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;does&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;have&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ancestor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;One fine body…&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FeatureContext&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;assertPageContainsText&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;skipped&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Great. Test failure. But we know it should work because we just did the exact same steps our test has in our browser. Why did it fail?&lt;/p&gt;
&lt;p&gt;Behat by default uses a headless driver called Goutte for all tests. It&amp;rsquo;s a very fast driver, but it doesn&amp;rsquo;t support Javascript. As the &lt;a href="http://mink.behat.org/"&gt;official documentation for Mink&lt;/a&gt; so perfectly states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Those browser emulators send a real HTTP requests against an application and parse the response content. They are very simple to run and configure, because this type of emulators can be written in any available programming language and can be run through console on servers without GUI. Headless emulators have both, advantages and disadvantages. Advantages are simplicity, speed and ability to run it without the need in real browser. But this type of browsers have one big disadvantage - they have no JS/AJAX support. So, you can’t test your rich GUI web applications with headless browsers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We need to use a different type of driver for our Javascript-dependant tests. These type of drivers are called &amp;lsquo;browser controllers&amp;rsquo;. They launch the browser you designate and then it does exactly what your tests say. This means your tests have the full Javascript support of your browser behind them.&lt;/p&gt;
&lt;p&gt;The easiest of these drivers to get setup and running is &lt;code&gt;Selenium2Driver&lt;/code&gt;. We&amp;rsquo;re going to use this with Google Chrome to get our tests passing. &lt;em&gt;Thanks to &lt;a href="https://twitter.com/colonelrosa"&gt;@ColonelRosa&lt;/a&gt; for pointing out Selenium2 support in Mink 1.3.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First of all you&amp;rsquo;ll need the &lt;code&gt;chromedriver&lt;/code&gt; on your machine, and have it available in your path. You&amp;rsquo;re able to download the driver from the &lt;a href="http://code.google.com/p/chromium/downloads/list"&gt;Google code project page&lt;/a&gt;. Or if you&amp;rsquo;re on a Mac and have homebrew installed, simply run &lt;code&gt;brew install chromedriver&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The last thing you&amp;rsquo;ll need is the WebDriver. Go to &lt;a href="http://seleniumhq.org/download/"&gt;http://seleniumhq.org/download/&lt;/a&gt; and then you want to choose the &amp;lsquo;Selenium Server&amp;rsquo;. As of writing, it&amp;rsquo;s version 2.16.1. This will download a Java &lt;code&gt;.jar&lt;/code&gt; file. Once you have this, simply run the following command in the terminal. It&amp;rsquo;s good idea to have this run in it&amp;rsquo;s own window or tab, because it must be running while the tests are active:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;java -jar /path/to/selenium-server-standalone-2.16.1.jar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You now have all the required tools.&lt;/p&gt;
&lt;p&gt;Now we just need to update our behat config, and our tests slightly. Update your &lt;code&gt;behat.yml&lt;/code&gt; to contain:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;://&lt;/span&gt;&lt;span class="n"&gt;twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;com&lt;/span&gt;&lt;span class="sr"&gt;/bootstrap/&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chrome&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;javascript_session&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;webdriver&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is telling behat that for our javascript tests, we want it to use the &lt;code&gt;WebDriver&lt;/code&gt; driver (&lt;code&gt;Selenium2&lt;/code&gt;). Also, that it is to use Google Chrome as the browser the driver controls.&lt;/p&gt;
&lt;p&gt;Now, we need to simply mark our test as being Javascript dependant, which is as easy as adding a &lt;code&gt;@javascript&lt;/code&gt; tag above the &lt;code&gt;Scenario&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Modal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dialog&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;javascript&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dialog&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/javascript.html&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Launch Modal&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;press&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Launch Modal&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;One fine body…&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now run behat.&lt;/p&gt;
&lt;p&gt;Damn. The tests are still failing. This is because when the button is pressed, Javascript animates the opening of the modal window, and hasn&amp;rsquo;t completed by the time the next step runs searching for the text. The animation hasn&amp;rsquo;t completed, and therefore the step fails.&lt;/p&gt;
&lt;p&gt;Well, we can get the test passing, and also add an additional definition that will make testing modals easier in the future. Lets update the scenario to the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;@javascript&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Open&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dialog&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;/javascript.html&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;Launch Modal&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;press&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;Launch Modal&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;Modal Heading&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;One fine body…&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;rsquo;ve added a new definition &lt;code&gt;I should see the modal "Modal Heading"&lt;/code&gt;. This will allow us to write other tests that depend on modal dialogs opening with various headings. Run behat to get the skeleton definition method and add it to your &lt;code&gt;FeatureContext.php&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;/**&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/^&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;([^&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;quot;$&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*/&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iShouldSeeTheModal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;(0 === jQuery.active &amp;amp;&amp;amp; 0 === jQuery(\&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;animated&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;).length)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assertElementContainsText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;#modal-from-dom .modal-header h3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;css&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;#modal-from-dom&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isVisible&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I&amp;rsquo;ll run through this method now line-by-line:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We use the &lt;code&gt;wait&lt;/code&gt; method to allow us to wait for the animation to complete. The first parameter sets 20 seconds to wait or until the following Javascript evaluates to true. We test to ensure that all Jquery ajax calls have completed, and that no elements are being animated.&lt;/li&gt;
&lt;li&gt;We want to check that the heading portion of the modal dialog contains the heading text that we pass through in the step. In our test, this is &amp;ldquo;Modal Heading&amp;rdquo;. So we use a CSS selector to do this.&lt;/li&gt;
&lt;li&gt;Finally, we just want to be sure that the modal dialog is actually visible on the page.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;rsquo;s it. One final change we can make is to move our Jquery wait check code into it&amp;rsquo;s own method so that we can use this in any other custom definitions we may create in future:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;protected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jqueryWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(0 === jQuery.active &amp;amp;&amp;amp; 0 === jQuery(\&amp;#39;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="n"&gt;animated&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;).length)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * @Then /^I should see the modal &amp;quot;([^&amp;quot;]*)&amp;quot;$/&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iShouldSeeTheModal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;jqueryWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assertElementContainsText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#modal-from-dom .modal-header h3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;css&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#modal-from-dom&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isVisible&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now run behat, and you should get a perfect test score:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;step&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Example code used in this post can be found on &lt;a href="https://github.com/davidwinter/Testing-Javascript-websites-with-Behat"&gt;Github&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Using Behat with Mink</title><link href="https://davidwinter.dev/2012/01/13/using-behat-with-mink/" rel="alternate"/><published>2012-01-13T00:00:00+00:00</published><updated>2012-01-13T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2012-01-13:/2012/01/13/using-behat-with-mink/</id><summary type="html">&lt;p&gt;Writing custom definitions&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;This is my second blog post on how to use Behat for your web application testing. If you haven&amp;rsquo;t already, be sure to read &lt;a href="/2011/11/06/getting-started-with-behat/"&gt;Getting started with Behat&lt;/a&gt; as this post continues on where that left off.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In my last post, I left you with hopefully enough knowledge to get started with some basic testing that comes for free, out of the box, by just installing &lt;a href="http://behat.org/"&gt;Behat&lt;/a&gt; and &lt;a href="http://mink.behat.org/"&gt;Mink&lt;/a&gt;. You were able to do that because Mink comes with around 34 bundled definitions.&lt;/p&gt;
&lt;p&gt;We created a very basic test to ensure that users were able to log into our example website:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sessions&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;their&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;need&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;able&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;website&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Login&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Login&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;myemail@test.com&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;password&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;mysecurepassword&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;press&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Login&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dashboard&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Welcome back&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Logout&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dashboard&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;follow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Logout&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Login&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So that we can work on this further, I&amp;rsquo;ve created a basic PHP script that we can use to play with. It&amp;rsquo;s written with the &lt;a href="http://silex.sensiolabs.org/"&gt;Silex&lt;/a&gt; micro-framework and doesn&amp;rsquo;t require any modification in order for us to write the tests in this blog post.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you do want to play along, clone the &lt;a href="https://github.com/davidwinter/Using-Behat-with-Mink"&gt;example from github&lt;/a&gt;, setup a virtual host. Then just be sure to update the &lt;code&gt;behat.yml&lt;/code&gt; file so that the &lt;code&gt;base_url&lt;/code&gt; points to your new virtual host.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you run &lt;code&gt;bin/behat&lt;/code&gt; now, it&amp;rsquo;ll run through the test and fail:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scenarios&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mf"&gt;11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;step&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;skipped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In our test, we&amp;rsquo;ve missed something! For the second scenario, we&amp;rsquo;ve not logged in the user! So they&amp;rsquo;re unable to access the &lt;code&gt;/dashboard&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If we focus on just the Logout scenario from here on, in order to log in the user, we could do something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Logout&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Login&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;myemail@test.com&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;password&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;mysecurepassword&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;press&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Login&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dashboard&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;follow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Logout&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Login&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is basically duplicating the steps from the above login scenario. Running this, the tests now pass. Excellent. Are we finished? No. The test above isn&amp;rsquo;t very tidy because we just copy and pasted code. It&amp;rsquo;d be so much nicer if we could write something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Logout&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;myemail@test.com&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;mysecurepassword&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dashboard&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;follow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Logout&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Login&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That makes our feature file a lot more readable, cleaner, and also provides us with a new custom definition that we can then use in other future tests. How do we make this work?&lt;/p&gt;
&lt;p&gt;When you run &lt;code&gt;bin/behat&lt;/code&gt; and you&amp;rsquo;ve added a custom definition, it&amp;rsquo;s very kind by providing you with an example template for creating the PHP code to have this new definition work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;/**&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/^&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;([^&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; with password &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;]*)&amp;quot;&lt;/span&gt;$&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*/&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iAmLoggedInAsWithPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;argument1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;argument2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PendingException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What do we do with this? Paste it directly into &lt;code&gt;features/bootstrap/FeatureContext.php&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we just need to use Mink to program the definition. Looking at the source for the &lt;a href="https://github.com/Behat/Mink/blob/master/src/Behat/Mink/Behat/Context/BaseMinkContext.php"&gt;base mink context&lt;/a&gt;, we can use the following methods to complete the definition:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;/**&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/^&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;([^&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; with password &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;]*)&amp;quot;&lt;/span&gt;$&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*/&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iAmLoggedInAsWithPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;email&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pressButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Login&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Saving, and then running &lt;code&gt;bin/behat&lt;/code&gt; again, the tests will now pass. And you&amp;rsquo;ve just created your first custom definition.&lt;/p&gt;
&lt;p&gt;There is one final change we could make to this. As our definition is using all existing definitions, we could future proof it by changing it to the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;/**&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/^&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;([^&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; with password &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;]*)&amp;quot;&lt;/span&gt;$&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*/&lt;/span&gt;
&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iAmLoggedInAsWithPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Step&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;I am on &amp;quot;/&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Step&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;I fill in &amp;quot;email&amp;quot; with &amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;$&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;#39;),&lt;/span&gt;
&lt;span class="s"&gt;        new Step\When(&amp;#39;I fill in &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; with &amp;quot;&amp;#39;.$password.&amp;#39;&amp;quot;&amp;#39;),&lt;/span&gt;
&lt;span class="s"&gt;        new Step\When(&amp;#39;I press &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;Login&lt;/span&gt;&amp;quot;&lt;span class="s"&gt;&amp;#39;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In order to use the above, be sure to update the &lt;code&gt;use&lt;/code&gt; statement at the top of the file so it contains the last line of the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;use Behat\Behat\Context\ClosuredContextInterface,
    Behat\Behat\Context\TranslatedContextInterface,
    Behat\Behat\Context\BehatContext,
    Behat\Behat\Exception\PendingException,
    Behat\Behat\Context\Step;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s all there is to it when creating custom definitions. The Mink source is a great way to look at how the out-of-the-box definitions work.&lt;/p&gt;</content></entry><entry><title>Setup rbenv on Mac OS X</title><link href="https://davidwinter.dev/2011/12/10/setup-rbenv-on-mac-os-x/" rel="alternate"/><published>2011-12-10T00:00:00+00:00</published><updated>2011-12-10T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2011-12-10:/2011/12/10/setup-rbenv-on-mac-os-x/</id><summary type="html">&lt;p&gt;Some quick setup instructions on getting rbenv installed on Lion&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://github.com/sstephenson/rbenv"&gt;rbenv&lt;/a&gt; is a quick way to get different ruby versions installed on your OS, without interfering with any default installs it may provide.&lt;/p&gt;
&lt;p&gt;Run the following commands:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;brew update
brew install rbenv
brew install ruby-build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In your bash profile file, ensure that the following is included:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;eval &amp;quot;$(rbenv init -)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, install the latest version of ruby:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;rbenv install 1.9.3-p0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Run the following to set &lt;code&gt;rbenv&lt;/code&gt; to use this new version of ruby.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;rbenv global 1.9.3-p0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Open a new shell and type &lt;code&gt;ruby --version&lt;/code&gt; and if you see &lt;code&gt;ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.2.0]&lt;/code&gt; then all is good and you&amp;rsquo;re all setup!&lt;/p&gt;
&lt;p&gt;One thing to note is that if you install a new gem that installs a binary, you&amp;rsquo;ll need to run &lt;code&gt;rbenv rehash&lt;/code&gt; afterwards in order for the binary to become available to you on the command line.&lt;/p&gt;</content></entry><entry><title>Getting started with Behat</title><link href="https://davidwinter.dev/2011/11/06/getting-started-with-behat/" rel="alternate"/><published>2011-11-06T00:00:00+00:00</published><updated>2011-11-06T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2011-11-06:/2011/11/06/getting-started-with-behat/</id><summary type="html">&lt;p&gt;A quick introduction on setting up Behat and writing your first test&lt;/p&gt;</summary><content type="html">&lt;p&gt;Where &lt;a href="https://github.com/sebastianbergmann/phpunit"&gt;PHPUnit&lt;/a&gt; is for testing the individual pieces of your code (unit testing), &lt;a href="http://behat.org/"&gt;Behat&lt;/a&gt; is a great tool for testing that an application behaves as expected when following a series of steps (functional testing). And for testing web applications, Behat ties in perfectly with &lt;a href="https://github.com/behat/mink"&gt;Mink&lt;/a&gt; to give you a bunch of web browser related tests out-of-the-box.&lt;/p&gt;
&lt;h2&gt;Install&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll be using &lt;a href="http://packagist.org/"&gt;composer&lt;/a&gt; to setup Behat and Mink. Create a &lt;code&gt;composer.json&lt;/code&gt; file in your project directory with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;{
    &amp;quot;require&amp;quot;: {
        &amp;quot;behat/behat&amp;quot;: &amp;quot;&amp;gt;=2.2.4&amp;quot;,
        &amp;quot;behat/mink&amp;quot;: &amp;quot;&amp;gt;=1.3.2&amp;quot;
    },

    &amp;quot;repositories&amp;quot;: {
        &amp;quot;behat/mink-deps&amp;quot;: { &amp;quot;composer&amp;quot;: { &amp;quot;url&amp;quot;: &amp;quot;behat.org&amp;quot; } }
    },

    &amp;quot;config&amp;quot;: {
        &amp;quot;bin-dir&amp;quot;: &amp;quot;bin/&amp;quot;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you don&amp;rsquo;t have the &lt;code&gt;composer.phar&lt;/code&gt; file already on your machine, simply run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;wget http://getcomposer.org/composer.phar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;php composer.phar install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Behat and Mink will then install into a &lt;code&gt;vendor&lt;/code&gt; and &lt;code&gt;bin&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;In your project directory, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;bin/behat --init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create a &lt;code&gt;features&lt;/code&gt; directory for you that contains the required files to get started.&lt;/p&gt;
&lt;p&gt;In order to setup Behat to use Mink, go into &lt;code&gt;features/bootstrap/FeatureContext.php&lt;/code&gt; and make sure that the following is defined:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;require_once&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__DIR__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/../../vendor/.composer/autoload.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FeatureContext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Behat&lt;/span&gt;\&lt;span class="n"&gt;Mink&lt;/span&gt;\&lt;span class="n"&gt;Behat&lt;/span&gt;\&lt;span class="n"&gt;Context&lt;/span&gt;\&lt;span class="n"&gt;MinkContext&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here you&amp;rsquo;re including the Mink library, and then ensuring that &lt;code&gt;FeatureContext&lt;/code&gt; extends from &lt;code&gt;MinkContext&lt;/code&gt;. You don&amp;rsquo;t really need to worry about what this file does for this example.&lt;/p&gt;
&lt;p&gt;Now let Behat know where it can test your web app from. In the root of your project directory, create a file called &lt;code&gt;behat.yml&lt;/code&gt; and include the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;://&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="sr"&gt;/mywebapp/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a &lt;a href="http://en.wikipedia.org/wiki/Yaml"&gt;YAML&lt;/a&gt; file, and you just need to update the &lt;code&gt;base_url&lt;/code&gt; value to whatever URL behat can access your app.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re ready to start.&lt;/p&gt;
&lt;h2&gt;Describe your application with features&lt;/h2&gt;
&lt;p&gt;Run the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;bin/behat -dl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should see a long list of available definitions that Behat currently has available to it. You can use these to write some powerful feature files that test your application.&lt;/p&gt;
&lt;p&gt;First, lets set the scene:&lt;/p&gt;
&lt;p&gt;Say on your homepage you have a login form and you want to make sure when someone logs in, they get directed to a dashboard page with a welcome message. You also want to check that when they logout, they are taken to the homepage with a confirmation message saying they&amp;rsquo;ve been logged out.&lt;/p&gt;
&lt;p&gt;Each test file has the &lt;code&gt;.feature&lt;/code&gt; extension that Behat uses to search for tests to run when calling the &lt;code&gt;behat&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;These feature files are written in the &lt;a href="http://docs.behat.org/guides/1.gherkin.html"&gt;Gherkin syntax&lt;/a&gt;. First of all you specify a particular feature you are testing. This is with the keyword &lt;code&gt;Feature:&lt;/code&gt; and a name. After which, you add a brief description of what the benefit, the role, and the actual feature is. You can have anything here, but it&amp;rsquo;s good practice to follow this format to make things readable.&lt;/p&gt;
&lt;p&gt;For each feature, you have a bunch of different scenarios that you want to test against to ensure it matches the expected behaviour. Scenarios consist of definitions that can be prefixed with either &lt;strong&gt;Given&lt;/strong&gt;, &lt;strong&gt;When&lt;/strong&gt;, &lt;strong&gt;Then&lt;/strong&gt; and &lt;strong&gt;And&lt;/strong&gt;. These keywords don&amp;rsquo;t mean anything, and are there purely to aid readability. &lt;strong&gt;Given&lt;/strong&gt; is where you&amp;rsquo;d set a bunch of pre-conditions for your test, &lt;strong&gt;When&lt;/strong&gt; for the steps taken to test, and &lt;strong&gt;Then&lt;/strong&gt; should describe what expected result you should see. &lt;strong&gt;And&lt;/strong&gt; can be used to include additional definitions per stage in a scenario.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sessions&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;their&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;need&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;able&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;website&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Login&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Login&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;myemail@test.com&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;password&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;mysecurepassword&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;press&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Login&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dashboard&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Welcome back&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Logout&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dashboard&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Logout&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Logged out&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Because we&amp;rsquo;ve written the steps in the available Mink definitions, we don&amp;rsquo;t need to write any PHP code! You can now run &lt;code&gt;bin/behat&lt;/code&gt; in the Terminal and you&amp;rsquo;ll see the result of the tests and whether your application conforms to them&amp;ndash;all lit up in green!&lt;/p&gt;
&lt;p&gt;These example tests may seem rather trivial, but having them means you have a safety net for your application, so that if you or someone changes something, however small or large to your code, and it breaks the expected application behaviour, your Behat tests will let you know sooner, when it&amp;rsquo;s easy to fix, rather than later when it&amp;rsquo;ll become a nightmare to track down.&lt;/p&gt;
&lt;p&gt;As an aside, it should be noted that Behat isn&amp;rsquo;t just great for us developers. If you&amp;rsquo;re working on a project for someone else, you can write up these feature files based on a clients spec, and get them to sign off of them for extra security and peace of mind for all parties.&lt;/p&gt;
&lt;p&gt;With the available definitions that Mink provides for Behat, you could quite easily write a ton of tests with just the definitions Mink provides. In a future blog post I&amp;rsquo;ll go on further to show how to write custom defintitions. Hopefully this is enough information to get you started and excited about using Behat in your projects.&lt;/p&gt;</content></entry><entry><title>Setting up Github Pages</title><link href="https://davidwinter.dev/2011/10/29/setting-up-github-pages/" rel="alternate"/><published>2011-10-29T00:00:00+01:00</published><updated>2011-10-29T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2011-10-29:/2011/10/29/setting-up-github-pages/</id><summary type="html">&lt;p&gt;Getting started with a Jekyll powered site and migrating from WordPress&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;ve not had time recently to keep my copy of &lt;a href="http://wordpress.org"&gt;WordPress&lt;/a&gt; up-to-date (yes, even though it&amp;rsquo;s &lt;a href="http://codex.wordpress.org/Installing/Updating_WordPress_with_Subversion"&gt;setup with SVN&lt;/a&gt;). I wanted something a little easier to manage. Having read good things about &lt;a href="http://pages.github.com/"&gt;Github Pages&lt;/a&gt;, I decided to take the plunge. I&amp;rsquo;ve now migrated this entire site over. It&amp;rsquo;s simple to setup, and also has &lt;a href="https://github.com/mojombo/jekyll/"&gt;Jekyll&lt;/a&gt; support enabled by default.&lt;/p&gt;
&lt;p&gt;Jekyll allows you to generate a static website from plain text post files, and templates. When you push your new posts to Github, Jekyll is run on the files and the static site is built and hosted for you.&lt;/p&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;To get started, install &lt;code&gt;jekyll&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo gem install jekyll
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you want to use &lt;a href="http://daringfireball.net/projects/markdown/"&gt;Markdown&lt;/a&gt; formatting in your posts, also install:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo gem install rdiscount
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you&amp;rsquo;ll need to create a git repository to manage your blog. There is a great &lt;a href="https://github.com/danielmcgraw/Jekyll-Base"&gt;Jekyll skeleton setup&lt;/a&gt; that I used here, so we&amp;rsquo;ll go ahead and clone that.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git clone https://github.com/danielmcgraw/Jekyll-Base.git yourgithubusername.github.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Be sure you replace &lt;code&gt;yourgithubusername&lt;/code&gt; with your Github username. This isn&amp;rsquo;t required on your local repo, but is for the repository you create on Github. It&amp;rsquo;s in this format so that Github can detect it&amp;rsquo;s a Github Pages site, and so it just makes sense to name it the same locally too.&lt;/p&gt;
&lt;p&gt;Now, we don&amp;rsquo;t want the git history for this skeleton setup, so remove the &lt;code&gt;.git&lt;/code&gt; directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd yourgithubusername.github.com/
rm -rf .git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To test things are working at this stage, open another terminal window in the same directory and run &lt;code&gt;jekyll --server&lt;/code&gt;. It keeps a process open, along with a webserver running on port 4000, monitoring file changes, and rebuilding the site automatically on the fly. So you&amp;rsquo;ll want to keep this terminal window open and running. You should now be able to see the generated site by visiting &lt;a href="http://localhost:4000"&gt;http://localhost:4000&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;jekyll&lt;/code&gt; builds the site, it puts the generated files into a &lt;code&gt;_site&lt;/code&gt; directory. You don&amp;rsquo;t want this directory in Git, so in the &lt;code&gt;.gitignore&lt;/code&gt; file add &lt;code&gt;_site&lt;/code&gt; to the bottom so that it&amp;rsquo;ll be ignored.&lt;/p&gt;
&lt;p&gt;Now on Github, create a new repository naming it in the same format &lt;code&gt;yourgithubusername.github.com&lt;/code&gt;. Then on your local machine:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git init
git add .
git commit -m &amp;quot;Initial commit. Jekyll base setup.&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then follow Github&amp;rsquo;s instructions on adding the remote reference, which is along the lines of (substitute &lt;code&gt;username&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;remote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="nv"&gt;@github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This pushes your site up to Github. After this initial push you can do a plain old &lt;code&gt;git push&lt;/code&gt; when you&amp;rsquo;ve made changes that are ready to be published.&lt;/p&gt;
&lt;p&gt;They say it can take up to 10 minutes for new sites to be generated when they are first pushed, however, it&amp;rsquo;ll likely be under a minute. They&amp;rsquo;ll email you either way when it&amp;rsquo;s done.&lt;/p&gt;
&lt;p&gt;You can then visit &lt;a href="http://yourgithubusername.github.com"&gt;http://yourgithubusername.github.com&lt;/a&gt; to see your new static site all built, and being served. Snappy isn&amp;rsquo;t it?&lt;/p&gt;
&lt;h2&gt;WordPress migration&lt;/h2&gt;
&lt;p&gt;There were two important things that I wanted to ensure kept the same during the migration to Github pages; the URLs for the posts, and the comments posted.&lt;/p&gt;
&lt;p&gt;My permalink structure on WordPress was:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/articles/%year%/%monthnum%/%day%/%postname%/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So to set this up on Jekyll, all I had to do was edit &lt;code&gt;_config.yml&lt;/code&gt; and set:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;permalink: /articles/:year/:month/:day/:title/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For comments, I had already been using &lt;a href="http://disqus.com/"&gt;Disqus&lt;/a&gt; on my WordPress install, so they already had that content. All I had to do was setup the Javascript to pull in those comments.  In the &lt;code&gt;_layouts/post.html&lt;/code&gt; file, all I did was add:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;disqus_thread&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;/*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;CONFIGURATION&lt;span class="w"&gt; &lt;/span&gt;VARIABLES:&lt;span class="w"&gt; &lt;/span&gt;EDIT&lt;span class="w"&gt; &lt;/span&gt;BEFORE&lt;span class="w"&gt; &lt;/span&gt;PASTING&lt;span class="w"&gt; &lt;/span&gt;INTO&lt;span class="w"&gt; &lt;/span&gt;YOUR&lt;span class="w"&gt; &lt;/span&gt;WEBPAGE&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*/
&lt;span class="w"&gt;    &lt;/span&gt;var&lt;span class="w"&gt; &lt;/span&gt;disqus_shortname&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt; &lt;/span&gt;&amp;#39;davidwinter&amp;#39;;&lt;span class="w"&gt; &lt;/span&gt;//&lt;span class="w"&gt; &lt;/span&gt;required:&lt;span class="w"&gt; &lt;/span&gt;replace&lt;span class="w"&gt; &lt;/span&gt;example&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;your&lt;span class="w"&gt; &lt;/span&gt;forum&lt;span class="w"&gt; &lt;/span&gt;shortname
&lt;span class="w"&gt;    &lt;/span&gt;var&lt;span class="w"&gt; &lt;/span&gt;disqus_url&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt; &lt;/span&gt;&amp;#39;http://davidwinter.me&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;raw&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;{{ page.url }}&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endraw&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&amp;#39;;

&lt;span class="w"&gt;    &lt;/span&gt;/*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;DON&amp;#39;T&lt;span class="w"&gt; &lt;/span&gt;EDIT&lt;span class="w"&gt; &lt;/span&gt;BELOW&lt;span class="w"&gt; &lt;/span&gt;THIS&lt;span class="w"&gt; &lt;/span&gt;LINE&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*/
&lt;span class="w"&gt;    &lt;/span&gt;(function()&lt;span class="w"&gt; &lt;/span&gt;{
&lt;span class="w"&gt;        &lt;/span&gt;var&lt;span class="w"&gt; &lt;/span&gt;dsq&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt; &lt;/span&gt;document.createElement(&amp;#39;script&amp;#39;);&lt;span class="w"&gt; &lt;/span&gt;dsq.type&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt; &lt;/span&gt;&amp;#39;text/javascript&amp;#39;;&lt;span class="w"&gt; &lt;/span&gt;dsq.async&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt; &lt;/span&gt;true;
&lt;span class="w"&gt;        &lt;/span&gt;dsq.src&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt; &lt;/span&gt;&amp;#39;http://&amp;#39;&lt;span class="w"&gt; &lt;/span&gt;+&lt;span class="w"&gt; &lt;/span&gt;disqus_shortname&lt;span class="w"&gt; &lt;/span&gt;+&lt;span class="w"&gt; &lt;/span&gt;&amp;#39;.disqus.com/embed.js&amp;#39;;
&lt;span class="w"&gt;        &lt;/span&gt;(document.getElementsByTagName(&amp;#39;head&amp;#39;)[0]&lt;span class="w"&gt; &lt;/span&gt;||&lt;span class="w"&gt; &lt;/span&gt;document.getElementsByTagName(&amp;#39;body&amp;#39;)[0]).appendChild(dsq);
&lt;span class="w"&gt;    &lt;/span&gt;})();
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;Please&lt;span class="w"&gt; &lt;/span&gt;enable&lt;span class="w"&gt; &lt;/span&gt;JavaScript&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;view&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://disqus.com/?ref_noscript&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;comments&lt;span class="w"&gt; &lt;/span&gt;powered&lt;span class="w"&gt; &lt;/span&gt;by&lt;span class="w"&gt; &lt;/span&gt;Disqus.&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://disqus.com&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;dsq-brlink&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;blog&lt;span class="w"&gt; &lt;/span&gt;comments&lt;span class="w"&gt; &lt;/span&gt;powered&lt;span class="w"&gt; &lt;/span&gt;by&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;logo-disqus&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Disqus&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The important stuff here is the &lt;code&gt;disqus_shortname&lt;/code&gt; and &lt;code&gt;disqus_url&lt;/code&gt; variables. These are required in order for Disqus to know which site comments to display, and the &lt;code&gt;disqus_url&lt;/code&gt; to know which page comments to render. Because my URLs are staying the same, this was easy by just using the domain and the &lt;code&gt;{% raw %}{{ page.url }}{% endraw %}&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;While you&amp;rsquo;re setting this up locally, you may want to include:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;disqus_developer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As the &lt;a href="http://docs.disqus.com/help/2/"&gt;help documents&lt;/a&gt; explain:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tells the Disqus service that you are testing the system on an inaccessible website, e.g. secured staging server or a local environment. If disqus_developer is off or undefined, Disqus&amp;rsquo; default behavior will be to attempt to read the location of your page and validate the URL. If unsuccessful, Disqus will not load. Use this variable to get around this restriction while you are testing on an inaccessible website.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Be sure that this is only set while testing the integration of Disqus. When you know it&amp;rsquo;s working locally, remove this variable, so that it doesn&amp;rsquo;t get pushed up to Github.&lt;/p&gt;
&lt;p&gt;And also, ensure that your &lt;code&gt;yourgithubusername.github.com&lt;/code&gt; address is added to your trusted domains list in the Disqus admin.&lt;/p&gt;
&lt;p&gt;One last thing that is quite important to bring over to my new Github Pages setup is all of my old posts&amp;hellip; duh. Depending on the size of your existing blog, you may just want to do this by hand. However, with 50+ posts, I wanted something automated.&lt;/p&gt;
&lt;p&gt;In WordPress, you can do an export of your posts under the Tools section of the left hand menu. Just select to export the posts, not all content, as you don&amp;rsquo;t need it.&lt;/p&gt;
&lt;p&gt;I wrote a &lt;a href="https://github.com/davidwinter/wordpress-to-jekyll"&gt;quick PHP tool&lt;/a&gt; to convert this exported data into Jekyll friendly post files. Once these have been generated, you can copy them into your &lt;code&gt;_posts&lt;/code&gt; directory, and Jekyll will generate the pages (if it&amp;rsquo;s still running).&lt;/p&gt;
&lt;p&gt;Push up to Github, and you&amp;rsquo;re all set. Just tinker around with the layouts and styling and you&amp;rsquo;ll then have a super fast, easy to manage, Jekyll powered Github Pages site.&lt;/p&gt;</content></entry><entry><title>Simple local web development with Apache and Dnsmasq</title><link href="https://davidwinter.dev/2011/06/18/simple-local-web-development-with-apache-and-dnsmasq/" rel="alternate"/><published>2011-06-18T00:00:00+01:00</published><updated>2011-06-18T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2011-06-18:/2011/06/18/simple-local-web-development-with-apache-and-dnsmasq/</id><summary type="html">&lt;p&gt;When you sit down and start work on a new project, what hoops do you have to jump through before you get your app running in your browser? There are more than likely always going to be two; creating a spoof domain that you create in &lt;code&gt;/etc/hosts&lt;/code&gt; so that …&lt;/p&gt;</summary><content type="html">&lt;p&gt;When you sit down and start work on a new project, what hoops do you have to jump through before you get your app running in your browser? There are more than likely always going to be two; creating a spoof domain that you create in &lt;code&gt;/etc/hosts&lt;/code&gt; so that you can access your app, and then a virtual host in Apache to make your files accessible. And it sucks having to do this each time. Don&amp;rsquo;t you wish you could just get on with the project as soon as you think of it? Read on.&lt;/p&gt;
&lt;p&gt;This was all inspired by &lt;a href="http://pow.cx/"&gt;Pow&lt;/a&gt;, a zero-configuration rack server created by &lt;a href="http://37signals.com/"&gt;37signals&lt;/a&gt;, that allows &lt;a href="http://rubyonrails.org/"&gt;Rails&lt;/a&gt; developers to do exactly that. By following convention over configuration, this can all be easily achieved. If you&amp;rsquo;re happy with accessing your apps via a spoof domain ending in &lt;code&gt;.dev&lt;/code&gt;, then follow these steps.&lt;/p&gt;
&lt;h2&gt;Requirements&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m assuming that you&amp;rsquo;ve got &lt;a href="http://mxcl.github.com/homebrew/"&gt;Homebrew&lt;/a&gt; installed, and that you&amp;rsquo;re using the built-in version of Apache on Mac OS X 10.6 Snow Leopard. However, these instructions should work fine on Linux too.&lt;/p&gt;
&lt;h2&gt;Dnsmasq&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.thekelleys.org.uk/dnsmasq/doc.html"&gt;Dnsmasq&lt;/a&gt; is a simple to install and setup mini DNS server. We&amp;rsquo;ll use it to setup a wildcard record of anything &lt;code&gt;.dev&lt;/code&gt; to point to your local machine.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;brew install dnsmasq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Follow the instructions after install about copying the configuration file to the expected place in &lt;code&gt;/usr/local/etc/dnsmasq&lt;/code&gt;, but don&amp;rsquo;t copy the &lt;code&gt;launchd&lt;/code&gt; settings yet. First of all edit &lt;code&gt;/usr/local/etc/dnsmasq&lt;/code&gt; and add the following at the very bottom:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m m-Double"&gt;127.0.0.1&lt;/span&gt;
&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m m-Double"&gt;127.0.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save. Now copy the &lt;code&gt;launchd&lt;/code&gt; settings across. Dnsmasq should now be running. You now need to tell your system to use it as a DNS server.&lt;/p&gt;
&lt;p&gt;Open up System Preferences and go to your Network settings and the DNS servers. Add &lt;code&gt;127.0.0.1&lt;/code&gt; to the top of the list, and then add whatever your normal internet facing DNS servers are beneath. I use &lt;a href="http://www.opendns.com/"&gt;OpenDNS&lt;/a&gt;. My DNS server list then looks like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;127.0.0.1&lt;/li&gt;
&lt;li&gt;208.67.222.222&lt;/li&gt;
&lt;li&gt;208.67.220.220&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Apply changes. Now open the Terminal and run a ping on anything ending with a &lt;code&gt;.dev&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ping test.dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It should start pinging your machine, &lt;code&gt;127.0.0.1&lt;/code&gt; - if it does, all is good.&lt;/p&gt;
&lt;p&gt;Now we can move onto configuring Apache for the last time.&lt;/p&gt;
&lt;h2&gt;Apache&lt;/h2&gt;
&lt;p&gt;Edit the following file, substituting &lt;code&gt;yourusername&lt;/code&gt; with whatever your system username is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/apache2/users/yourusername.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then make it look like the following, again replacing &lt;code&gt;yourusername&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;NameVirtualHost&lt;span class="w"&gt; &lt;/span&gt;*:80

&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;quot;/Users/yourusername/Sites/&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Options&lt;span class="w"&gt; &lt;/span&gt;Indexes&lt;span class="w"&gt; &lt;/span&gt;MultiViews&lt;span class="w"&gt; &lt;/span&gt;FollowSymLinks&lt;span class="w"&gt; &lt;/span&gt;Includes
&lt;span class="w"&gt;    &lt;/span&gt;AllowOverride&lt;span class="w"&gt; &lt;/span&gt;All
&lt;span class="w"&gt;    &lt;/span&gt;Order&lt;span class="w"&gt; &lt;/span&gt;allow,deny
&lt;span class="w"&gt;    &lt;/span&gt;Allow&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;all
&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;VirtualHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*:80&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;UseCanonicalName&lt;span class="w"&gt; &lt;/span&gt;off
&lt;span class="w"&gt;    &lt;/span&gt;VirtualDocumentRoot&lt;span class="w"&gt; &lt;/span&gt;/Users/yourusername/Sites/%0/public
&lt;span class="nt"&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save. And then run &lt;code&gt;sudo apachectl graceful&lt;/code&gt;. This will restart Apache. In the above configuration, we&amp;rsquo;re using Apache&amp;rsquo;s &lt;a href="http://httpd.apache.org/docs/2.2/mod/mod_vhost_alias.html"&gt;mod_vhost_alias&lt;/a&gt; module to dynamically configure virtual hosts and document roots on the fly.&lt;/p&gt;
&lt;h2&gt;Testing it all works&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir -p ~/Sites/test.dev/public
echo &amp;quot;test.dev&amp;quot; &amp;gt; ~/Sites/test.dev/public/index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now visit &lt;a href="http://test.dev/"&gt;http://test.dev/&lt;/a&gt; in your web browser. Hopefully you should see &lt;code&gt;test.dev&lt;/code&gt; - if so congratulations; you&amp;rsquo;re going to save so much time in the future now.&lt;/p&gt;</content><category term="apache"/><category term="dns"/><category term="dnsmasq"/><category term="mac"/><category term="macosx"/></entry><entry><title>Install APF on Ubuntu 11.04</title><link href="https://davidwinter.dev/2011/06/05/install-apf-on-ubuntu-11-04/" rel="alternate"/><published>2011-06-05T00:00:00+01:00</published><updated>2011-06-05T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2011-06-05:/2011/06/05/install-apf-on-ubuntu-11-04/</id><summary type="html">&lt;p&gt;I just setup a new Linode to host my new twitter app, &lt;a href="http://listsdj.com"&gt;lists dj&lt;/a&gt; and wanted to lock it down to basically Apache and SSH.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iptables&lt;/code&gt; gives me a headache, and I don&amp;rsquo;t want to spend a day learning how to use it. APF uses iptables, but the configuration …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I just setup a new Linode to host my new twitter app, &lt;a href="http://listsdj.com"&gt;lists dj&lt;/a&gt; and wanted to lock it down to basically Apache and SSH.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iptables&lt;/code&gt; gives me a headache, and I don&amp;rsquo;t want to spend a day learning how to use it. APF uses iptables, but the configuration is so much easier.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo aptitude install apf-firewall
sudo nano /etc/apf-firewall/conf.apf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you&amp;rsquo;re using Linode, you&amp;rsquo;ll need to ensure the following line and configuration value is set:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;SET_MONOKERN=&amp;quot;1&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is because &lt;code&gt;iptables&lt;/code&gt; is installed into the kernel rather than as a package. Not setting this will prevent APF from running.&lt;/p&gt;
&lt;p&gt;Then, to open the desired ports, just update this line with the port numbers, separated with a space:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;IG_TCP_CPORTS=&amp;quot;22 80 443&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And ensure this line is set:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;DEVEL_MODE=&amp;quot;0&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This means that the firewall isn&amp;rsquo;t in development mode, otherwise your rules will be flushed every 5 minutes. Handy if you&amp;rsquo;re experimenting with new rules and don&amp;rsquo;t want to be locked out of your server. Worse case, you&amp;rsquo;d only have to wait 5 minutes before being able to get back in. But because I&amp;rsquo;m only opening ports, I don&amp;rsquo;t need this. Just make sure you leave your SSH port open!&lt;/p&gt;
&lt;p&gt;Lastly, open up this file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/default/apf-firewall
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And set it to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;RUN=&amp;quot;yes&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you can start up APF and you&amp;rsquo;re all protected:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apf-firewall start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="apf"/><category term="security"/><category term="ubuntu"/></entry><entry><title>Setup UFW on Ubuntu 11.04</title><link href="https://davidwinter.dev/2011/06/05/setup-ufw-on-ubuntu-11-04/" rel="alternate"/><published>2011-06-05T00:00:00+01:00</published><updated>2011-06-05T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2011-06-05:/2011/06/05/setup-ufw-on-ubuntu-11-04/</id><summary type="html">&lt;p&gt;Not much more than a few hours have passed since I posted my &lt;a href="/2011/06/05/install-apf-on-ubuntu-11-04/"&gt;APF setup howto&lt;/a&gt;, but I&amp;rsquo;ve found something even simpler.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ufw&lt;/code&gt; - uncomplicated firewall. It does exactly as it says on the tin.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo aptitude install ufw
sudo ufw allow 22
sudo ufw enable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s ssh sorted …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Not much more than a few hours have passed since I posted my &lt;a href="/2011/06/05/install-apf-on-ubuntu-11-04/"&gt;APF setup howto&lt;/a&gt;, but I&amp;rsquo;ve found something even simpler.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ufw&lt;/code&gt; - uncomplicated firewall. It does exactly as it says on the tin.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo aptitude install ufw
sudo ufw allow 22
sudo ufw enable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s ssh sorted, and the firewall is enabled. It&amp;rsquo;s important to allow port 22 first before enabling, otherwise you&amp;rsquo;ll get locked out. You can see the status of the firewall by running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ufw status verbose
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And to allow Apache traffic:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ufw allow 80
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s it. Outgoing traffic is allowed by default. Everything else is blocked. Also, all of these rules are saved transparently, so you don&amp;rsquo;t have to worry about things like that. Reboot away, and everything will just work.&lt;/p&gt;
&lt;p&gt;If you need to disable &lt;code&gt;ufw&lt;/code&gt; just run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ufw disable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="security"/><category term="server"/><category term="ubuntu"/><category term="ufw"/></entry><entry><title>PHP development on Mac OS X 10.6 Snow Leopard</title><link href="https://davidwinter.dev/2011/05/27/php-development-on-mac-os-x-10-6-snow-leopard/" rel="alternate"/><published>2011-05-27T00:00:00+01:00</published><updated>2011-05-27T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2011-05-27:/2011/05/27/php-development-on-mac-os-x-10-6-snow-leopard/</id><summary type="html">&lt;p&gt;Having a reliable and easy to use developer environment on my Mac is essential for my work, and the odd project I work on.&lt;/p&gt;
&lt;p&gt;I original used the &lt;a href="http://www.entropy.ch/software/macosx/php/"&gt;Entropy PHP packages&lt;/a&gt; as they were so easy to install, and &lt;em&gt;just worked&lt;/em&gt;. Unfortunately, Marc Liyanage had stopped updating the packages with …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Having a reliable and easy to use developer environment on my Mac is essential for my work, and the odd project I work on.&lt;/p&gt;
&lt;p&gt;I original used the &lt;a href="http://www.entropy.ch/software/macosx/php/"&gt;Entropy PHP packages&lt;/a&gt; as they were so easy to install, and &lt;em&gt;just worked&lt;/em&gt;. Unfortunately, Marc Liyanage had stopped updating the packages with new OS X releases, so I then tried alternatives such as &lt;a href="/2010/01/02/apache-php-and-mongodb-on-mac-os-x-10.6-snow-leopard/"&gt;Macports&lt;/a&gt;, and more recently &lt;a href="http://www.mamp.info/"&gt;MAMP&lt;/a&gt;. However, it hasn&amp;rsquo;t been working out of late, so I went in search of alternatives.&lt;/p&gt;
&lt;p&gt;For a long shot, I visited Marc&amp;rsquo;s PHP page and noticed that he is now &lt;a href="http://php-osx.liip.ch/"&gt;endorsing a project&lt;/a&gt; which forked off from his own. Like his packages, it uses the default Apache install that comes with OS X, but uses their own alternative PHP package. It installs into &lt;code&gt;/usr/local&lt;/code&gt; so that it doesn&amp;rsquo;t interfere with anything else. So here are some steps to get this all up and running.&lt;/p&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;Before I started, I uninstalled Macports and MAMP. Not required, but I didn&amp;rsquo;t want any of those packages to interfere or conflict with the new install of PHP. I now use &lt;a href="http://mxcl.github.com/homebrew/"&gt;homebrew&lt;/a&gt; as a replacement to Macports for tools that I require (such as MongoDB and MySQL).&lt;/p&gt;
&lt;h3&gt;Install PHP for OS X&lt;/h3&gt;
&lt;p&gt;Install PHP via &lt;a href="http://php-osx.liip.ch"&gt;http://php-osx.liip.ch&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;curl -s http://php-osx.liip.ch/install.sh | bash -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;ll ask for your password so that it can install to &lt;code&gt;/usr/local&lt;/code&gt;. If you&amp;rsquo;re cautious of running a shell script from a webpage&amp;ndash;as you should be!&amp;ndash;why not view the source in your browser first to be sure all is as it should.&lt;/p&gt;
&lt;h3&gt;Setup path&lt;/h3&gt;
&lt;p&gt;If you want to use any of the PHP tools via the command line, such as &lt;code&gt;pear&lt;/code&gt; or &lt;code&gt;pecl&lt;/code&gt;, it&amp;rsquo;s best if you add the new PHP &lt;code&gt;bin&lt;/code&gt; to your path. I updated mine to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/local/php5/bin:/usr/local/bin:$PATH&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The important part here is the inclusion of &lt;code&gt;/usr/local/php5/bin&lt;/code&gt;. You&amp;rsquo;ll then want to open a new terminal window so that the path update takes effect. Check by running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;echo $PATH
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you&amp;rsquo;re going to use &lt;code&gt;pear&lt;/code&gt; or &lt;code&gt;pecl&lt;/code&gt;, it may be worth checking that it&amp;rsquo;s configured to use the correct &lt;code&gt;php.ini&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Run the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pear config-get php_ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If it doesn&amp;rsquo;t say:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/usr/local/php5/lib/php.ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo pear config-set php_ini /usr/local/php5/lib/php.ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then just check that &lt;code&gt;pecl&lt;/code&gt; has the same config set:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pecl config-get php_ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That should now be PHP setup and running.&lt;/p&gt;
&lt;h2&gt;Easy Apache configuration&lt;/h2&gt;
&lt;p&gt;With some great pointers by &lt;a href="http://www.456bereastreet.com/archive/201104/apache_with_virtual_hosts_php_and_ssi_on_mac_os_x_106/"&gt;Roger Johansson&lt;/a&gt; here is a great way to make configuring Apache easy for projects you work on. You&amp;rsquo;ll need to edit two files. One will make some hostname aliases to your local machine so that you can access a project via a url such as &lt;code&gt;http://myproject.local&lt;/code&gt;. The other file is the Apache configuration file for your user, where you specify the server name and document root location. Here we go:&lt;/p&gt;
&lt;p&gt;Edit &lt;code&gt;/etc/apache2/users/yourusername.conf&lt;/code&gt; substituting &lt;code&gt;yourusername&lt;/code&gt; with the actual username you use on your Mac. Update it so that it looks like this (again updating the path with your actual username):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;NameVirtualHost&lt;span class="w"&gt; &lt;/span&gt;*:80

&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;quot;/Users/yourusername/Sites/&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Options&lt;span class="w"&gt; &lt;/span&gt;Indexes&lt;span class="w"&gt; &lt;/span&gt;MultiViews&lt;span class="w"&gt; &lt;/span&gt;FollowSymLinks&lt;span class="w"&gt; &lt;/span&gt;Includes
&lt;span class="w"&gt;    &lt;/span&gt;AllowOverride&lt;span class="w"&gt; &lt;/span&gt;All
&lt;span class="w"&gt;    &lt;/span&gt;Order&lt;span class="w"&gt; &lt;/span&gt;allow,deny
&lt;span class="w"&gt;    &lt;/span&gt;Allow&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;all
&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;VirtualHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*:80&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;ServerName&lt;span class="w"&gt; &lt;/span&gt;myproject.local
&lt;span class="w"&gt;    &lt;/span&gt;DocumentRoot&lt;span class="w"&gt; &lt;/span&gt;/Users/yourusername/Sites/myproject.local
&lt;span class="nt"&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now edit &lt;code&gt;/etc/hosts&lt;/code&gt; and add to the bottom:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;127.0.0.1&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;myproject&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now reload Apache, and you should be all set:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apachectl graceful
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;re all set now! Hopefully this will make PHP development easier for you, as it has done for me.&lt;/p&gt;</content><category term="apache"/><category term="cli"/><category term="mac"/><category term="macosx"/><category term="php"/></entry><entry><title>Merging MKV files together</title><link href="https://davidwinter.dev/2011/05/21/merging-mkv-files-together/" rel="alternate"/><published>2011-05-21T00:00:00+01:00</published><updated>2011-05-21T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2011-05-21:/2011/05/21/merging-mkv-files-together/</id><content type="html">&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkvmerge -o merged_file.mkv file1.mkv + file2.mkv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="cli"/><category term="mac"/><category term="mkv"/><category term="unix"/></entry><entry><title>Mod rewrite rules in htaccess files</title><link href="https://davidwinter.dev/2011/02/08/mod-rewrite-rules-in-htaccess-files/" rel="alternate"/><published>2011-02-08T00:00:00+00:00</published><updated>2011-02-08T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2011-02-08:/2011/02/08/mod-rewrite-rules-in-htaccess-files/</id><content type="html">&lt;p&gt;Rewrite rules in an htaccess file don&amp;rsquo;t need to leading slash, otherwise they won&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;Be warned. Don&amp;rsquo;t waste two hours wondering why it isn&amp;rsquo;t working.&lt;/p&gt;</content><category term="apache"/><category term="httpd"/></entry><entry><title>Authentication with CodeIgniter 2.0</title><link href="https://davidwinter.dev/2011/01/29/authentication-with-codeigniter-2-0/" rel="alternate"/><published>2011-01-29T00:00:00+00:00</published><updated>2011-01-29T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2011-01-29:/2011/01/29/authentication-with-codeigniter-2-0/</id><summary type="html">&lt;p&gt;I&amp;rsquo;ve started using &lt;a href="http://codeigniter.com/"&gt;CodeIgniter&lt;/a&gt; again recently, and have noticed that my &lt;a href="/2009/02/21/authentication-with-codeigniter/"&gt;how-to on implementing basic authentication&lt;/a&gt; could do with an upgrade for version 2.0.&lt;/p&gt;
&lt;p&gt;The process is identical. We subclass the base &lt;code&gt;CI_Controller&lt;/code&gt; class. This simply checks whether a logged in session is present. If not, it redirects …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;ve started using &lt;a href="http://codeigniter.com/"&gt;CodeIgniter&lt;/a&gt; again recently, and have noticed that my &lt;a href="/2009/02/21/authentication-with-codeigniter/"&gt;how-to on implementing basic authentication&lt;/a&gt; could do with an upgrade for version 2.0.&lt;/p&gt;
&lt;p&gt;The process is identical. We subclass the base &lt;code&gt;CI_Controller&lt;/code&gt; class. This simply checks whether a logged in session is present. If not, it redirects the user to a sessions controller that can handle the logging in of a user. Once the user is logged in, the controller acts as normal.&lt;/p&gt;
&lt;p&gt;So, first up, lets create our basic subclass:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MY_Controller&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CI_Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;session&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;loggedin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sessions/login&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, this needs to be saved to &lt;code&gt;application/core&lt;/code&gt;. This is important. You can&amp;rsquo;t add it to &lt;code&gt;application/library&lt;/code&gt; like with the previous how-to. There have been some changes to CI that require the change. This new class is also auto-loaded automatically.&lt;/p&gt;
&lt;p&gt;Now, the sessions controller needs to extend &lt;code&gt;CI_Controller&lt;/code&gt;. Users don&amp;rsquo;t need to be authenticated to access this controller.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CI_Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;session&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;header&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;login&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;footer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;email&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;set_userdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;loggedin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;unset_userdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;loggedin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Your &lt;code&gt;login&lt;/code&gt; view will look something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Login&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;form_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sessions/authenticate&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;dl&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;dt&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;form_label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Email&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;user_email&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/dt&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;dd&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;form_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;user[email]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;user_email&amp;#39;&lt;/span&gt;
        &lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/dd&amp;gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;dt&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;form_label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;user_password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/dt&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;dd&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;form_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;user[password]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;user_password&amp;#39;&lt;/span&gt;
        &lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/dd&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/dl&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;form_submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;submit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Login&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;site_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;form_close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s a basic &lt;code&gt;user&lt;/code&gt; model you could use. It includes hashing with extra salt security:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CI_Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;salt&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;salt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;users&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;email&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="o"&gt;.$&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;users&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;email&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hash&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now all that&amp;rsquo;s left is to change the parent classes of the controllers that we want protected from &lt;code&gt;CI_Controller&lt;/code&gt; to &lt;code&gt;MY_Controller&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Admin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MY_Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Authentication is now in place.&lt;/p&gt;</content><category term="codeigniter"/><category term="howto"/><category term="php"/></entry><entry><title>A simple chat room with WebSockets</title><link href="https://davidwinter.dev/2010/11/21/a-simple-chat-room-with-websockets/" rel="alternate"/><published>2010-11-21T00:00:00+00:00</published><updated>2010-11-21T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2010-11-21:/2010/11/21/a-simple-chat-room-with-websockets/</id><content type="html">&lt;p&gt;Sorry, I promised a blog post, but instead you get a link to bitbucket with the source of a basic chat app written using WebSockets.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bitbucket.org/davidwinter/websockets-chat/src"&gt;https://bitbucket.org/davidwinter/websockets-chat/src&lt;/a&gt;&lt;/p&gt;</content><category term="howto"/><category term="javascript"/><category term="websockets"/></entry><entry><title>Setting up SSH host shortnames</title><link href="https://davidwinter.dev/2010/08/22/setting-up-ssh-host-shortnames/" rel="alternate"/><published>2010-08-22T00:00:00+01:00</published><updated>2010-08-22T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2010-08-22:/2010/08/22/setting-up-ssh-host-shortnames/</id><summary type="html">&lt;p&gt;Here&amp;rsquo;s an example setup to create SSH host shortnames. On you local computer, add the following to &lt;code&gt;~/.ssh/config&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Host server1
HostName server1.internet.com
User david

Host server2
HostName server2.internet.com
User david

Host *
User davidwinter
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now with this file saved, you can ssh into &lt;code&gt;server2.internet …&lt;/code&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here&amp;rsquo;s an example setup to create SSH host shortnames. On you local computer, add the following to &lt;code&gt;~/.ssh/config&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Host server1
HostName server1.internet.com
User david

Host server2
HostName server2.internet.com
User david

Host *
User davidwinter
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now with this file saved, you can ssh into &lt;code&gt;server2.internet.com&lt;/code&gt; with just the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh server2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will save you having to type out:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;david&lt;/span&gt;&lt;span class="nv"&gt;@server2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;internet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And if you have &lt;a href="/2010/08/22/ssh-and-public-key-authentication/"&gt;public key authentication&lt;/a&gt; setup, it makes the process even smoother. Adding the wildcard host record at the bottom allows you to specify a default username to use for other servers to the ones you&amp;rsquo;ve not specified above.&lt;/p&gt;</content><category term="cli"/><category term="linux"/><category term="mac"/><category term="osx"/><category term="ssh"/><category term="unix"/></entry><entry><title>SSH and public key authentication</title><link href="https://davidwinter.dev/2010/08/22/ssh-and-public-key-authentication/" rel="alternate"/><published>2010-08-22T00:00:00+01:00</published><updated>2010-08-22T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2010-08-22:/2010/08/22/ssh-and-public-key-authentication/</id><summary type="html">&lt;p&gt;Fed up with having to type your password in each time you log into a server over SSH? Me too. Down with passwords, and in with public key authentication!&lt;/p&gt;
&lt;p&gt;First thing to do, is to check that you have a SSH key setup already on your local computer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ~/.ssh …&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Fed up with having to type your password in each time you log into a server over SSH? Me too. Down with passwords, and in with public key authentication!&lt;/p&gt;
&lt;p&gt;First thing to do, is to check that you have a SSH key setup already on your local computer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ~/.ssh
ls
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you see some files in there starting with &lt;code&gt;id_&lt;/code&gt;, like &lt;code&gt;id_rsa.pub&lt;/code&gt; or &lt;code&gt;id_tsa.pub&lt;/code&gt;, you&amp;rsquo;re all set. If not, you&amp;rsquo;ll need to generate these files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh-keygen -t rsa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;At the prompts you see, you can just hit enter to accept the defaults.&lt;/p&gt;
&lt;p&gt;With your public key now in place, we need to transfer that to the server we want to log into.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;scp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;id_rsa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="nv"&gt;@remote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Don&amp;rsquo;t forget the colon at the end. This has now transfered the public key over. Now you need to log into the remote server (with your password - last time, I promise):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="nv"&gt;@remote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, check if there is a &lt;code&gt;.ssh&lt;/code&gt; directory on the remote server in your home directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ~/.ssh/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If there isn&amp;rsquo;t:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir ~/.ssh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now move the public key to a file named &lt;code&gt;authorized_keys&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mv ~/id_rsa.pub ~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we need to set the correct permissions to ensure no one can tamper with these files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And you&amp;rsquo;re done. Now you can logout, and log back in again - and all going well (if your SSH server has been setup correctly - by default it usually is), you won&amp;rsquo;t be prompted for a password.&lt;/p&gt;
&lt;p&gt;If it doesn&amp;rsquo;t work, one problem I encountered was where the actual home directory permissions weren&amp;rsquo;t set to &lt;code&gt;700&lt;/code&gt;. So try:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;chmod 700 /home/username
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All done.&lt;/p&gt;</content><category term="cli"/><category term="howto"/><category term="linux"/><category term="mac"/><category term="osx"/><category term="ssh"/><category term="unix"/></entry><entry><title>Using Capistrano to deploy Mercurial changes</title><link href="https://davidwinter.dev/2010/08/22/using-capistrano-to-deploy-mercurial-changes/" rel="alternate"/><published>2010-08-22T00:00:00+01:00</published><updated>2010-08-22T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2010-08-22:/2010/08/22/using-capistrano-to-deploy-mercurial-changes/</id><summary type="html">&lt;p&gt;We have a few production servers at work, and we have a central &lt;a href="http://bitbucket.org"&gt;bitbucket&lt;/a&gt; repository to store our core code. Once we make a change on our testing server (!), we used to have to commit, push changes to bitbucket, and then ssh into each server, then pull changes, and update …&lt;/p&gt;</summary><content type="html">&lt;p&gt;We have a few production servers at work, and we have a central &lt;a href="http://bitbucket.org"&gt;bitbucket&lt;/a&gt; repository to store our core code. Once we make a change on our testing server (!), we used to have to commit, push changes to bitbucket, and then ssh into each server, then pull changes, and update each repository. A pain in the backside! Enter &lt;a href="http://www.capify.org"&gt;Capistrano&lt;/a&gt;. A ruby ssh automation tool. In a few simple steps you can create a recipe file that will let you do this all with one command.&lt;/p&gt;
&lt;p&gt;On the machine where you&amp;rsquo;d like to kick this all off&amp;mdash;where you&amp;rsquo;ll be pushing the changes from&amp;mdash;install Capistrano (requires &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; and &lt;a href="http://rubygems.org/"&gt;RubyGems&lt;/a&gt; to be installed):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo gem install capistrano
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Capistrano is opinionated software; meaning it makes a &lt;a href="http://www.capify.org/index.php/Getting_Started"&gt;few assumptions&lt;/a&gt; about your server setup which you&amp;rsquo;ll need to comply with. Mainly that either you have &lt;a href="/2010/08/22/ssh-and-public-key-authentication/"&gt;public key authentication&lt;/a&gt; setup to connect to these remote servers, or, you use the same password across all of them.&lt;/p&gt;
&lt;p&gt;Now, create a &lt;code&gt;capfile&lt;/code&gt;, perhaps in your home directory, and here is an example that you can modify for your own setup:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;production_servers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;srv1.internet.com&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;srv2.internet.com&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;push_deploy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;production_servers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cd /local/path/to/repos &amp;amp;&amp;amp; hg push&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cd /remote/path/to/repos &amp;amp;&amp;amp; hg pull &amp;amp;&amp;amp; hg update&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With that now saved, you can issue this task with the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cap push_deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will first of all run a local command to push the changes to bitbucket. After that is complete, it&amp;rsquo;ll connect to each of the production servers listed, pull changes and then update the repository. And that&amp;rsquo;s it. You don&amp;rsquo;t need to do anything else. Piece of &lt;a href="http://fatcakehole.tumblr.com/"&gt;cake&lt;/a&gt;.&lt;/p&gt;</content><category term="capistrano"/><category term="howto"/><category term="linux"/><category term="mac"/><category term="osx"/><category term="ruby"/><category term="servers"/><category term="ssh"/></entry><entry><title>Using o2 PAYG mobile broadband</title><link href="https://davidwinter.dev/2010/06/19/using-o2-payg-mobile-broadband/" rel="alternate"/><published>2010-06-19T00:00:00+01:00</published><updated>2010-06-19T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2010-06-19:/2010/06/19/using-o2-payg-mobile-broadband/</id><summary type="html">&lt;p&gt;Our internet connection via our landline has been dead since Tuesday afternoon, so I&amp;rsquo;ve needed an alternative connection in the meantime to give me my twitter fix!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d kept an eye on the o2 pay-as-you-go mobile broadband for a while, because it offered the cheapest, noncommittal setup. A …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Our internet connection via our landline has been dead since Tuesday afternoon, so I&amp;rsquo;ve needed an alternative connection in the meantime to give me my twitter fix!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d kept an eye on the o2 pay-as-you-go mobile broadband for a while, because it offered the cheapest, noncommittal setup. A one off £20 for the USB dongle, and then as little as £2 for 500MB for a 24 hour period.&lt;/p&gt;
&lt;p&gt;So I plug in the dongle and we get a nice little installer to set everything up; installing drivers and the o2 Mobile Connect application. The annoying thing is that if you install going this route, you can only connect if you have this app open. You can&amp;rsquo;t just use system preferences. Also, turns out this &amp;lsquo;handy&amp;rsquo; installer program then blocks you from getting to the installation files again, and the dongle will refuse to do anything unless Mobile Connect is open (you&amp;rsquo;ll get a red light on the dongle when it&amp;rsquo;s being evil).&lt;/p&gt;
&lt;p&gt;So, what can you do?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag &lt;code&gt;Mobile Connect.app&lt;/code&gt; to the trash from your Applications directory.&lt;/li&gt;
&lt;li&gt;Then head into System &amp;gt; Library &amp;gt; Extensions and delete &lt;code&gt;ZTEUSBCDCACMData.kext&lt;/code&gt; and &lt;code&gt;ZTEUSBMassStorageFilter.kext&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Go into Network in System Preferences and remove the devices starting with ZTEUSB.&lt;/li&gt;
&lt;li&gt;Then restart your Mac.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, let&amp;rsquo;s install things a different route giving everyone more flexibility.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Plug in the dongle and when the CD Icon appears on the desktop, open it up, but rather than double clicking on the installer, right click on it and select &amp;lsquo;Show Package Contents&amp;rsquo;.&lt;/li&gt;
&lt;li&gt;Now head to Contents then Resources. Now double click on the &lt;code&gt;drv.pkg&lt;/code&gt; file and install this only.&lt;/li&gt;
&lt;li&gt;Once complete, restart your Mac again.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And now to configure the connection:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open System Preferences, and go to the Network pane.&lt;/li&gt;
&lt;li&gt;You should have three new items in there. Click on ZTEUSBModem.&lt;/li&gt;
&lt;li&gt;Set the telephone number to &lt;code&gt;*99#&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Username to &lt;code&gt;o2bb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Password to &lt;code&gt;password&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click on Advanced. Select Vendor; Generic, Model; GPRS (GSM/3G) and set the APN to &lt;code&gt;m-bb.o2.co.uk&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click on OK and then Apply.&lt;/li&gt;
&lt;li&gt;Now you can click &amp;lsquo;Connect&amp;rsquo; and all should work fine.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That is of course, besides the crappy image compression and caching o2 force onto you! Need to find a solution for that next.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: Here&amp;rsquo;s a solution for getting around the image compression, and Javascript injection; use a SSH SOCKS proxy. Works a treat.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open up &lt;code&gt;Terminal.app&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;ssh -ND 9999 username@yourserver.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Enter your password if/when prompted (you may have key authentication setup)&lt;/li&gt;
&lt;li&gt;That&amp;rsquo;s the SOCKS proxy setup. Now go to System Preferences and open the network connection.&lt;/li&gt;
&lt;li&gt;Click on ZTEUSBModem.&lt;/li&gt;
&lt;li&gt;Then Advanced, Proxies&lt;/li&gt;
&lt;li&gt;Check the SOCKS Proxy and enter in &lt;code&gt;localhost&lt;/code&gt; and &lt;code&gt;9999&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click OK and then Apply.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All done. You should now get perfect images and no longer have Javascript inserted into all webpages. Both of which weren&amp;rsquo;t clearly mentioned when purchasing my dongle.&lt;/p&gt;</content><category term="howto"/><category term="internet"/><category term="mac"/><category term="o2"/><category term="osx"/></entry><entry><title>Redirecting Apache traffic to a maintenance page</title><link href="https://davidwinter.dev/2010/05/03/redirecting-apache-traffic-to-a-maintenance-page/" rel="alternate"/><published>2010-05-03T00:00:00+01:00</published><updated>2010-05-03T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2010-05-03:/2010/05/03/redirecting-apache-traffic-to-a-maintenance-page/</id><summary type="html">&lt;p&gt;Here&amp;rsquo;s a simple solution to redirect users to a maintenance page in Apache. This rewrite rule can stay in your config (&lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt; or &lt;code&gt;.htaccess&lt;/code&gt;) all the time; all that you need to enable it is to create the file &lt;code&gt;maintenance.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first rewrite condition checks to see if …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here&amp;rsquo;s a simple solution to redirect users to a maintenance page in Apache. This rewrite rule can stay in your config (&lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt; or &lt;code&gt;.htaccess&lt;/code&gt;) all the time; all that you need to enable it is to create the file &lt;code&gt;maintenance.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first rewrite condition checks to see if the file exists, and only if it does, will it redirect all traffic to it. The second rewrite condition is there to prevent an infinite loop, by  only redirecting traffic to files other than &lt;code&gt;maintenance.html&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;RewriteEngine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;On&lt;/span&gt;

&lt;span class="n"&gt;RewriteCond&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DOCUMENT_ROOT&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;maintenance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;
&lt;span class="n"&gt;RewriteCond&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;REQUEST_FILENAME&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;maintenance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="n"&gt;RewriteRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;maintenance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="apache"/><category term="howto"/><category term="web"/></entry><entry><title>Install Mercurial on CentOS 4</title><link href="https://davidwinter.dev/2010/04/18/install-mercurial-on-centos-4/" rel="alternate"/><published>2010-04-18T00:00:00+01:00</published><updated>2010-04-18T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2010-04-18:/2010/04/18/install-mercurial-on-centos-4/</id><summary type="html">&lt;p&gt;We&amp;rsquo;ve finally moved to Mercurial at work (well, we didn&amp;rsquo;t exactly move from anywhere, but that&amp;rsquo;s another story&amp;hellip;). Our production server is running CentOS 4, which comes installed with Python 2.3.4. Mercurial requires 2.4. No Python updates available in the yum repository. What to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;We&amp;rsquo;ve finally moved to Mercurial at work (well, we didn&amp;rsquo;t exactly move from anywhere, but that&amp;rsquo;s another story&amp;hellip;). Our production server is running CentOS 4, which comes installed with Python 2.3.4. Mercurial requires 2.4. No Python updates available in the yum repository. What to do?&lt;/p&gt;
&lt;p&gt;First up, install the latest version of Python to a location that won&amp;rsquo;t interfere with the system:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;wget http://www.python.org/ftp/python/2.6.5/Python-2.6.5.tgz
tar xvfz Python-2.6.5.tgz
cd Python-2.6.5/
./configure --prefix=/opt
make
sudo make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we just want to test the new Python install:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/opt/bin/python -V
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This should come back with &lt;code&gt;Python 2.6.5&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we install Mercurial, but tell it to use this new install of Python, rather than the default:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ..
wget http://mercurial.selenic.com/release/mercurial-1.5.1.tar.gz
tar xvfz mercurial-1.5.1.tar.gz
cd mercurial-1.5.1/
sudo make install PYTHON=/opt/bin/python PREFIX=/opt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now to test Mercurial has installed successfully:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/opt/bin/hg --version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This should print out somewhere the version 1.5.1. Now Mercurial is setup, add it to &lt;code&gt;/usr/local/bin&lt;/code&gt; so that it&amp;rsquo;s available in the path:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ln -s /opt/bin/hg /usr/local/bin/hg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That wasn&amp;rsquo;t too painful was it?&lt;/p&gt;</content><category term="centos"/><category term="mercurial"/><category term="python"/></entry><entry><title>Apache, PHP and MongoDB on Mac OS X 10.6 Snow Leopard</title><link href="https://davidwinter.dev/2010/01/02/apache-php-and-mongodb-on-mac-os-x-10-6-snow-leopard/" rel="alternate"/><published>2010-01-02T00:00:00+00:00</published><updated>2010-01-02T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2010-01-02:/2010/01/02/apache-php-and-mongodb-on-mac-os-x-10-6-snow-leopard/</id><summary type="html">&lt;p&gt;&lt;a href="http://www.mongodb.org/display/DOCS/Home"&gt;MongoDB&lt;/a&gt; (from &amp;ldquo;humongous&amp;rdquo;) is a scalable, high-performance, open source, schema-free, document-oriented database.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a lot of &lt;a href="http://delicious.com/search?p=mongodb&amp;amp;chk=&amp;amp;context=popular|&amp;amp;fr=del_icio_us&amp;amp;lc="&gt;buzz&lt;/a&gt; brewing about it, so I wanted to give it a try with PHP on my development Mac. The following is how I went about installing Apache, PHP and MongoDB on Snow Leopard …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.mongodb.org/display/DOCS/Home"&gt;MongoDB&lt;/a&gt; (from &amp;ldquo;humongous&amp;rdquo;) is a scalable, high-performance, open source, schema-free, document-oriented database.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a lot of &lt;a href="http://delicious.com/search?p=mongodb&amp;amp;chk=&amp;amp;context=popular|&amp;amp;fr=del_icio_us&amp;amp;lc="&gt;buzz&lt;/a&gt; brewing about it, so I wanted to give it a try with PHP on my development Mac. The following is how I went about installing Apache, PHP and MongoDB on Snow Leopard. You must have installed the &lt;a href="http://developer.apple.com/tools/xcode/"&gt;Xcode&lt;/a&gt; developer tools (found on the Snow Leopard install DVD) and &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt; for this to all work.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s install Apache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo port install apache2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nice and simple. Now we can move onto PHP:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo port install php5 +apache2 +pear
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To enable PHP for Apache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd /opt/local/apache2/modules
sudo /opt/local/apache2/bin/apxs -a -e -n &amp;quot;php5&amp;quot; libphp5.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I like to make some alias commands for starting, restarting and stopping Apache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mate ~/.bashrc

alias apache-start=&amp;quot;sudo /opt/local/apache2/bin/apachectl start&amp;quot;
alias apache-restart=&amp;quot;sudo /opt/local/apache2/bin/apachectl restart&amp;quot;
alias apache-stop=&amp;quot;sudo /opt/local/apache2/bin/apachectl stop&amp;quot;

source ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we can make a few changes to the Apache config so that we can use our Sites directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo mate /opt/local/apache2/conf/httpd.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I&amp;rsquo;m using Textmate here (&lt;code&gt;mate&lt;/code&gt;), but you can use any editor you wish, like &lt;code&gt;nano&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Change the &lt;code&gt;DocumentRoot&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;DocumentRoot &amp;quot;/Users/davidwinter/Sites&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then update the &lt;code&gt;&amp;lt;Directory&amp;gt;&lt;/code&gt; path to the updated &lt;code&gt;DocumentRoot&lt;/code&gt; path.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;lt;Directory &amp;quot;/Users/davidwinter/Sites&amp;quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We also want to enable &lt;code&gt;index.php&lt;/code&gt; as a directory index file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;IfModule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;dir_module&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;DirectoryIndex&lt;span class="w"&gt; &lt;/span&gt;index.html&lt;span class="w"&gt; &lt;/span&gt;index.php
&lt;span class="nt"&gt;&amp;lt;/IfModule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then add the PHP mime type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;IfModule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mime_module&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;...
&lt;span class="w"&gt;    &lt;/span&gt;AddType&lt;span class="w"&gt; &lt;/span&gt;application/x-httpd-php&lt;span class="w"&gt; &lt;/span&gt;.php
&lt;span class="w"&gt;    &lt;/span&gt;AddType&lt;span class="w"&gt; &lt;/span&gt;application/x-httpd-php-source&lt;span class="w"&gt; &lt;/span&gt;.phps
&lt;span class="nt"&gt;&amp;lt;/IfModule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we need to setup the &lt;code&gt;php.ini&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo cp /opt/local/etc/php5/php.ini-development /opt/local/etc/php5/php.ini

sudo mate /opt/local/etc/php5/php.ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;My &lt;a href="http://php.net/manual/en/timezones.php"&gt;timezone&lt;/a&gt; is for London:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;date.timezone = Europe/London
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we can get onto installing MongoDB (this will install the latest stable version as of time of writing - 1.2.1):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo port install mongodb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then the PHP MongoDB extension:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo pecl install mongo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll need to add the extension to the bottom of your &lt;code&gt;php.ini&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo mate /opt/local/etc/php5/php.ini

extension=mongo.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now startup Apache using the &lt;code&gt;alias&lt;/code&gt; created earlier:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;apache-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you create a file in your Sites directory, called &lt;code&gt;test.php&lt;/code&gt;, and add the following to it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="nb"&gt;phpinfo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then visit the page in your browser; &lt;a href="http://localhost/test.php"&gt;http://localhost/test.php&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can then scroll down the page and you should see a section titled &amp;lsquo;mongo&amp;rsquo;. This means the extension is working!&lt;/p&gt;
&lt;p&gt;Now we need to startup MongoDB:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir -p ~/data/db
mongod --dbpath ~/data/db/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Almost there, now a simple MongoDB test in PHP:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="c1"&gt;// Connect:&lt;/span&gt;
&lt;span class="nv"&gt;$connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Mongo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Select database:&lt;/span&gt;
&lt;span class="nv"&gt;$db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;my_db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Select collection:&lt;/span&gt;
&lt;span class="nv"&gt;$films&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;films&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$frwl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;From Russia With Love&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;year&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1963&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;actor&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Sean Connery&amp;#39;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Save array to collection:&lt;/span&gt;
&lt;span class="nv"&gt;$films&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$frwl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$gf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Goldfinger&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;year&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1964&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;actor&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Sean Connery&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;girl&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Pussy Galore&amp;#39;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$films&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Count documents in collection:&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$films&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Title&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Year&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Actor&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Girl&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$films&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$film&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$film&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$film&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;year&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$film&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;actor&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$film&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;girl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;endforeach&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Very exciting stuff. More to follow.&lt;/p&gt;</content><category term="apache"/><category term="mac"/><category term="macports"/><category term="mongodb"/><category term="osx"/><category term="php"/><category term="web"/></entry><entry><title>Remove startup scripts on Ubuntu</title><link href="https://davidwinter.dev/2009/10/20/remove-startup-scripts-on-ubuntu/" rel="alternate"/><published>2009-10-20T00:00:00+01:00</published><updated>2009-10-20T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2009-10-20:/2009/10/20/remove-startup-scripts-on-ubuntu/</id><content type="html">&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo update-rc.d -f script_name remove
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="cli"/><category term="ubuntu"/><category term="unix"/></entry><entry><title>Convert git repository to mercurial</title><link href="https://davidwinter.dev/2009/10/17/convert-git-repository-to-mercurial/" rel="alternate"/><published>2009-10-17T00:00:00+01:00</published><updated>2009-10-17T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2009-10-17:/2009/10/17/convert-git-repository-to-mercurial/</id><summary type="html">&lt;p&gt;Ensure that the mercurial convert extension is enabled:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nano ~/.hgrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside that file add:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[extensions]&lt;/span&gt;
&lt;span class="na"&gt;hgext.convert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save. Now do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;hg convert my-git-repo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create a new directory called &lt;code&gt;my-git-repo-hg&lt;/code&gt;. This will appear empty at first, so do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd my-git-repo-hg
hg checkout
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All of your files will appear …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Ensure that the mercurial convert extension is enabled:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nano ~/.hgrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside that file add:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[extensions]&lt;/span&gt;
&lt;span class="na"&gt;hgext.convert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save. Now do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;hg convert my-git-repo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create a new directory called &lt;code&gt;my-git-repo-hg&lt;/code&gt;. This will appear empty at first, so do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd my-git-repo-hg
hg checkout
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All of your files will appear and you&amp;rsquo;re ready to go.&lt;/p&gt;</content><category term="git"/><category term="hg"/><category term="mercurial"/></entry><entry><title>Enable PHP error logging</title><link href="https://davidwinter.dev/2009/07/14/enable-php-error-logging/" rel="alternate"/><published>2009-07-14T00:00:00+01:00</published><updated>2009-07-14T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2009-07-14:/2009/07/14/enable-php-error-logging/</id><content type="html">&lt;p&gt;In php.ini:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;display_errors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Off&lt;/span&gt;
&lt;span class="n"&gt;log_errors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;
&lt;span class="n"&gt;error_log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Make the log file, and writable by www-data:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;touch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="php"/><category term="ubuntu"/></entry><entry><title>PHP and nginx on Ubuntu: the easy way</title><link href="https://davidwinter.dev/2009/06/13/php-and-nginx-the-easy-way/" rel="alternate"/><published>2009-06-13T00:00:00+01:00</published><updated>2009-06-13T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2009-06-13:/2009/06/13/php-and-nginx-the-easy-way/</id><summary type="html">&lt;p&gt;I&amp;rsquo;ve now changed my slice from running lighttpd to nginx. Here&amp;rsquo;s the simplest way, in around 6 commands, to get PHP up and running via FastCGI.&lt;/p&gt;
&lt;h2&gt;Install and setup&lt;/h2&gt;
&lt;p&gt;Install PHP 5:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo aptitude install php5-cgi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install nginx:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo aptitude install nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create PHP 5 FastCGI start-up script …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;ve now changed my slice from running lighttpd to nginx. Here&amp;rsquo;s the simplest way, in around 6 commands, to get PHP up and running via FastCGI.&lt;/p&gt;
&lt;h2&gt;Install and setup&lt;/h2&gt;
&lt;p&gt;Install PHP 5:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo aptitude install php5-cgi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install nginx:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo aptitude install nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create PHP 5 FastCGI start-up script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/init.d/php-fastcgi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside, put:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;BIND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;127&lt;/span&gt;.0.0.1:9000
&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;www-data
&lt;span class="nv"&gt;PHP_FCGI_CHILDREN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;
&lt;span class="nv"&gt;PHP_FCGI_MAX_REQUESTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;

&lt;span class="nv"&gt;PHP_CGI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/php-cgi
&lt;span class="nv"&gt;PHP_CGI_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;basename&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$PHP_CGI&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;PHP_CGI_ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;- USER=&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt; PATH=/usr/bin PHP_FCGI_CHILDREN=&lt;/span&gt;&lt;span class="nv"&gt;$PHP_FCGI_CHILDREN&lt;/span&gt;&lt;span class="s2"&gt; PHP_FCGI_MAX_REQUESTS=&lt;/span&gt;&lt;span class="nv"&gt;$PHP_FCGI_MAX_REQUESTS&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$PHP_CGI&lt;/span&gt;&lt;span class="s2"&gt; -b &lt;/span&gt;&lt;span class="nv"&gt;$BIND&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;RETVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;

start&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Starting PHP FastCGI: &amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;start-stop-daemon&lt;span class="w"&gt; &lt;/span&gt;--quiet&lt;span class="w"&gt; &lt;/span&gt;--start&lt;span class="w"&gt; &lt;/span&gt;--background&lt;span class="w"&gt; &lt;/span&gt;--chuid&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--exec&lt;span class="w"&gt; &lt;/span&gt;/usr/bin/env&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$PHP_CGI_ARGS&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;RETVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$PHP_CGI_NAME&lt;/span&gt;&lt;span class="s2"&gt;.&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
stop&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Stopping PHP FastCGI: &amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;killall&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;-w&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$PHP_CGI&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;RETVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$PHP_CGI_NAME&lt;/span&gt;&lt;span class="s2"&gt;.&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;start&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;start
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;stop&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;stop
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;restart&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;stop
&lt;span class="w"&gt;      &lt;/span&gt;start
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;*&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Usage: php-fastcgi {start|stop|restart}&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$RETVAL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Make start-up script executable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo chmod +x /etc/init.d/php-fastcgi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Launch PHP:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/php-fastcgi start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Launch at start-up:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo update-rc.d php-fastcgi defaults
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s it. All installed and ready to go.&lt;/p&gt;
&lt;h2&gt;Test&lt;/h2&gt;
&lt;p&gt;In your server config, add the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;fastcgi_pass&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;fastcgi_index&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;fastcgi_param&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;SCRIPT_FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;fastcgi_script_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;fastcgi_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Restart nginx:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/nginx restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create a file in your web root (in the example above, /var/www/nginx-default/test.php):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="nb"&gt;phpinfo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Visit the page in your browser and you should see the standard PHP info page. And you&amp;rsquo;re done.&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="http://tomasz.sterna.tv/2009/04/php-fastcgi-with-nginx-on-ubuntu/"&gt;Aberration&lt;/a&gt;&lt;/p&gt;</content><category term="howto"/><category term="nginx"/><category term="php"/><category term="ubuntu"/></entry><entry><title>Authentication with CodeIgniter</title><link href="https://davidwinter.dev/2009/02/21/authentication-with-codeigniter/" rel="alternate"/><published>2009-02-21T00:00:00+00:00</published><updated>2009-02-21T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2009-02-21:/2009/02/21/authentication-with-codeigniter/</id><summary type="html">&lt;p&gt;Here&amp;rsquo;s how I do some basic authentication for a controller in &lt;a href="http://codeigniter.com/"&gt;CodeIgniter&lt;/a&gt;. It basically consists of creating a new class that extends the default &lt;code&gt;Controller&lt;/code&gt; class. You then sub-class this on any controller that requires authentication.&lt;/p&gt;
&lt;p&gt;Create your authentication controller in &lt;code&gt;system/application/libraries&lt;/code&gt; and call it &lt;code&gt;MY_Controller.php …&lt;/code&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here&amp;rsquo;s how I do some basic authentication for a controller in &lt;a href="http://codeigniter.com/"&gt;CodeIgniter&lt;/a&gt;. It basically consists of creating a new class that extends the default &lt;code&gt;Controller&lt;/code&gt; class. You then sub-class this on any controller that requires authentication.&lt;/p&gt;
&lt;p&gt;Create your authentication controller in &lt;code&gt;system/application/libraries&lt;/code&gt; and call it &lt;code&gt;MY_Controller.php&lt;/code&gt;. It&amp;rsquo;s important that you prefix the controller name with &lt;code&gt;MY_&lt;/code&gt;, or whatever you have specified &lt;code&gt;$config['subclass_prefix']&lt;/code&gt; as in your configuration.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MY_Controller&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;session&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;loggedin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Location: /sessions/login&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This basically checks if the session data for &lt;code&gt;loggedin&lt;/code&gt; is set to &lt;code&gt;true&lt;/code&gt;. If not, it&amp;rsquo;ll redirect the user to the &lt;code&gt;/sessions/login&lt;/code&gt; URL. This means we have to create a basic controller to handle the sessions.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;session&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;header&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sessions/login&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;footer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;set_userdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;loggedin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Location: /&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Location: /sessions/login&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;unset_userdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;loggedin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Location: /&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;login&lt;/code&gt; view is a basic form with fields for &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; that submits to &lt;code&gt;/sessions/authenticate&lt;/code&gt;. This controller then loads the user model and checks that a user with the username and password exists. If so, it sets the session data for &lt;code&gt;loggedin&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; and redirects the user back to the default controller. If not, it takes the user back to the login page.&lt;/p&gt;
&lt;p&gt;Then to implement the authentication in a controller, simply do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SecretPlace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MY_Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;s a good idea to &lt;a href="http://codeigniter.com/user_guide/libraries/sessions.html"&gt;store your session data in your database&lt;/a&gt; and encrypt your cookies with &lt;code&gt;$config['sess_encrypt_cookie'] = TRUE;&lt;/code&gt; in &lt;code&gt;config.php&lt;/code&gt;. That way people won&amp;rsquo;t be able to snoop around and try to trick your application into thinking they&amp;rsquo;re authenticated.&lt;/p&gt;</content><category term="codeigniter"/><category term="howto"/><category term="php"/></entry><entry><title>A simple PHP delicious REST example with pecl_http</title><link href="https://davidwinter.dev/2008/11/24/a-simple-php-pecl_http-example-with-delicious/" rel="alternate"/><published>2008-11-24T00:00:00+00:00</published><updated>2008-11-24T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-11-24:/2008/11/24/a-simple-php-pecl_http-example-with-delicious/</id><summary type="html">&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="nv"&gt;$username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your_username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your_password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;$password&lt;/span&gt;&lt;span class="s2"&gt;@api.del.icio.us/v1/posts/recent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HTTP_METH_GET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getBody&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll probably need to view the source in your browser to see the output.&lt;/p&gt;
&lt;p&gt;The second argument isn&amp;rsquo;t required in this …&lt;/p&gt;</summary><content type="html">&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="nv"&gt;$username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your_username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your_password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;$password&lt;/span&gt;&lt;span class="s2"&gt;@api.del.icio.us/v1/posts/recent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HTTP_METH_GET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getBody&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll probably need to view the source in your browser to see the output.&lt;/p&gt;
&lt;p&gt;The second argument isn&amp;rsquo;t required in this call, because &lt;code&gt;HttpRequest&lt;/code&gt; defaults to a &lt;code&gt;GET&lt;/code&gt; request anyway, but it&amp;rsquo;s just helpful to see where you can specify the different HTTP methods. The others being, post, put and delete.&lt;/p&gt;</content><category term="code"/><category term="delicious"/><category term="example"/><category term="http"/><category term="pecl_http"/><category term="php"/><category term="rest"/></entry><entry><title>Install pecl_http for PHP</title><link href="https://davidwinter.dev/2008/11/24/install-pecl_http-for-php/" rel="alternate"/><published>2008-11-24T00:00:00+00:00</published><updated>2008-11-24T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-11-24:/2008/11/24/install-pecl_http-for-php/</id><summary type="html">&lt;p&gt;You will probably want to ensure that &lt;code&gt;curl&lt;/code&gt; supports &lt;code&gt;https&lt;/code&gt; before getting underway:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;curl -V
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Check that the output contains &lt;code&gt;https&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt;: curl -V
curl 7.19.2 (i386-apple-darwin9.5.0) libcurl/7.19.2 OpenSSL/0.9.8i zlib/1.2.3
Protocols: tftp ftp telnet dict http file https …&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;You will probably want to ensure that &lt;code&gt;curl&lt;/code&gt; supports &lt;code&gt;https&lt;/code&gt; before getting underway:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;curl -V
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Check that the output contains &lt;code&gt;https&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt;: curl -V
curl 7.19.2 (i386-apple-darwin9.5.0) libcurl/7.19.2 OpenSSL/0.9.8i zlib/1.2.3
Protocols: tftp ftp telnet dict http file https ftps
Features: Largefile NTLM SSL libz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If it doesn&amp;rsquo;t:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo port deactivate curl
sudo port install curl +ssl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once you have &lt;code&gt;curl&lt;/code&gt; with &lt;code&gt;https&lt;/code&gt; support:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo pecl install pecl_http
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you followed my previous &lt;a href="/2008/11/22/php5-lighttpd-and-imagick-on-mac-os-x-leopard/"&gt;howto&lt;/a&gt;, you&amp;rsquo;ll want to move the module to the location specified in your &lt;code&gt;php.ini&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo cp /opt/local/lib/php/extensions/no-debug-non-zts-20060613/http.so /opt/local/lib/php/extensions
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Restart &lt;code&gt;lighttpd&lt;/code&gt; and then you&amp;rsquo;ll be good to go.&lt;/p&gt;</content><category term="howto"/><category term="http"/><category term="lighttpd"/><category term="mac"/><category term="macports"/><category term="osx"/><category term="pecl_http"/><category term="php"/></entry><entry><title>Install PHP5, lighttpd and Imagick on Mac OS X Leopard</title><link href="https://davidwinter.dev/2008/11/22/php5-lighttpd-and-imagick-on-mac-os-x-leopard/" rel="alternate"/><published>2008-11-22T00:00:00+00:00</published><updated>2008-11-22T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-11-22:/2008/11/22/php5-lighttpd-and-imagick-on-mac-os-x-leopard/</id><summary type="html">&lt;p&gt;It&amp;rsquo;s a little tricky getting a nice clean install of &lt;a href="http://www.php.net"&gt;PHP5&lt;/a&gt; for OS X 10.5. The packages that I always used to depend on over at &lt;a href="http://www.entropy.ch/software/macosx/php/"&gt;Entropy&lt;/a&gt; don&amp;rsquo;t seem to work anymore. At least not for Leopard. A great shame.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m now switching to &lt;a href="http://www.lighttpd.net"&gt;lighttpd&lt;/a&gt; for …&lt;/p&gt;</summary><content type="html">&lt;p&gt;It&amp;rsquo;s a little tricky getting a nice clean install of &lt;a href="http://www.php.net"&gt;PHP5&lt;/a&gt; for OS X 10.5. The packages that I always used to depend on over at &lt;a href="http://www.entropy.ch/software/macosx/php/"&gt;Entropy&lt;/a&gt; don&amp;rsquo;t seem to work anymore. At least not for Leopard. A great shame.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m now switching to &lt;a href="http://www.lighttpd.net"&gt;lighttpd&lt;/a&gt; for my development server, so have come up with the following recipe to install PHP5 and the great &lt;a href="http://www.php.net/imagick"&gt;Imagick&lt;/a&gt; extension for image manipulation.&lt;/p&gt;
&lt;p&gt;Follow these instructions at your own risk! They worked fine on my setup but I can&amp;rsquo;t guarantee they will for you.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;a href="http://developer.apple.com/technology/xcode.html"&gt;Xcode&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now update MacPorts:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo port selfupdate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install lighttpd:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo port install lighttpd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install the startup item and copy the default configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;launchctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Library&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;LaunchDaemons&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;macports&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plist&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now we install PHP with the FastCGI, MySQL and Pear variants.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo port install php5 +fastcgi +mysql5 +pear
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In order for this to work, I had to disable the port &lt;code&gt;perl5.8&lt;/code&gt; by using the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo port deactivate perl5.8
sudo port activate perl5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then run the command again and it should succeed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo port install php5 +fastcgi +mysql5 +pear
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy over the default PHP configuration:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo cp /opt/local/etc/php.ini-dist /opt/local/etc/php.ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now open up the PHP configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo mate /opt/local/etc/php.ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add the following line to the file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cgi.fix_pathinfo=1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Find &lt;code&gt;extension_dir = "./"&lt;/code&gt; and replace it with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;extension_dir = &amp;quot;/opt/local/lib/php/extensions&amp;quot;
extension=imagick.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Edit the lighttpd configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo mate /opt/local/etc/lighttpd/lighttpd.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ensure that the following is uncommented:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;fastcgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;.php&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;socket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/run/lighttpd/php-fastcgi.socket&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;bin-path&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/opt/local/bin/php-cgi&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And also make lighttpd run as the user &lt;code&gt;www&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;server.username = &amp;quot;www&amp;quot;
server.groupname = &amp;quot;www&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add the following if you want to be able to use your &lt;code&gt;Sites&lt;/code&gt; directory in your home directory. I also changed the default document root to the OS X default:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;server.modules += (&amp;quot;mod_userdir&amp;quot;)
userdir.path = &amp;quot;Sites&amp;quot;
userdir.basepath = &amp;quot;/Users/&amp;quot;
server.document-root = &amp;quot;/Library/WebServer/Documents&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ensure that &lt;code&gt;"mod_fastcgi",&lt;/code&gt; is uncommented.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now we need to setup a few directories, and make the user &lt;code&gt;www&lt;/code&gt; the owner for them:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now install ImageMagick:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo port install imagemagick
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now we need to download the Imagick PHP module. I was hoping this would be as easy as &lt;code&gt;sudo pecl install imagick&lt;/code&gt;, however I got an error for that, and so a manual build and install of the module is necessary:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;curl -O http://pecl.php.net/get/imagick-2.2.1.tgz
tar xvfz imagick-2.2.1.tgz
cd imagick-2.2.1/
phpize
./configure --with-imagick=/opt/local
make
sudo make install
sudo cp /opt/local/lib/php/extensions/no-debug-non-zts-20060613/imagick.so /opt/local/lib/php/extensions
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And finally, you can then run LightTPD with the following. The &lt;code&gt;-D&lt;/code&gt; flag tells lighttpd not to run in the background&amp;ndash;you don&amp;rsquo;t need to use it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;lighttpd -f /opt/local/etc/lighttpd/lighttpd.conf -D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should then be able to visit a PHP file in your browser to test that it works. A simple test file would be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="nv"&gt;$img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Imagick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pic.jpg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;rotateImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#fff&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-type: image/jpeg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is just a simple Imagick rotate on an image.&lt;/p&gt;</content><category term="howto"/><category term="imagick"/><category term="lighttpd"/><category term="mac"/><category term="php"/></entry><entry><title>lighttpd and PHP on CentOS 5</title><link href="https://davidwinter.dev/2008/06/22/lighttpd-and-php-on-centos-5/" rel="alternate"/><published>2008-06-22T00:00:00+01:00</published><updated>2008-06-22T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-06-22:/2008/06/22/lighttpd-and-php-on-centos-5/</id><summary type="html">&lt;p&gt;Here&amp;rsquo;s a quick run down on getting &lt;a href="http://www.lighttpd.net/"&gt;lighttpd&lt;/a&gt; and &lt;a href="http://php.net"&gt;php&lt;/a&gt; running on &lt;a href="http://www.centos.org/"&gt;CentOS 5&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;yum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fastcgi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;
&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;
&lt;span class="n"&gt;touch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fastcgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;
&lt;span class="n"&gt;chown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ini&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add in &lt;code&gt;php.ini&lt;/code&gt; the following; &lt;code&gt;cgi …&lt;/code&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here&amp;rsquo;s a quick run down on getting &lt;a href="http://www.lighttpd.net/"&gt;lighttpd&lt;/a&gt; and &lt;a href="http://php.net"&gt;php&lt;/a&gt; running on &lt;a href="http://www.centos.org/"&gt;CentOS 5&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;yum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fastcgi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;
&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;
&lt;span class="n"&gt;touch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fastcgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;
&lt;span class="n"&gt;chown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lighttpd&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ini&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add in &lt;code&gt;php.ini&lt;/code&gt; the following; &lt;code&gt;cgi.fix_pathinfo = 1&lt;/code&gt;. Save and close the file.&lt;/p&gt;
&lt;p&gt;Now open up &lt;code&gt;/etc/lighttpd/lighttpd.conf&lt;/code&gt;. Uncomment the following line &lt;code&gt;"mod_fastcgi",&lt;/code&gt; from the &lt;code&gt;server.modules&lt;/code&gt; option. Then ensure that the following is uncommented:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;fastcgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;.php&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;socket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/run/lighttpd/php-fastcgi.socket&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;bin-path&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/bin/php-cgi&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file. Now create a test file, &lt;code&gt;/srv/www/lighttpd/index.php&lt;/code&gt; and just include &lt;code&gt;&amp;lt;?php phpinfo(); ?&amp;gt;&lt;/code&gt;. Now open your &lt;a href="http://getfirefox.com"&gt;favourite browser&lt;/a&gt; and visit &lt;a href="http://localhost/index.php"&gt;http://localhost/index.php&lt;/a&gt;. You should be greeted with a friendly PHP page, and you&amp;rsquo;re set to go.&lt;/p&gt;</content><category term="centos"/><category term="howto"/><category term="lighttpd"/><category term="php"/></entry><entry><title>Mac OS X/HFS+ case-insensitive? Why?</title><link href="https://davidwinter.dev/2008/05/17/mac-os-xhfs-case-insensitive-why/" rel="alternate"/><published>2008-05-17T00:00:00+01:00</published><updated>2008-05-17T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-05-17:/2008/05/17/mac-os-xhfs-case-insensitive-why/</id><summary type="html">&lt;p&gt;I just found out that HFS+, the preferred file system for Mac OS X, is case-insensitive when it comes to files and directories. I don&amp;rsquo;t understand why? It&amp;rsquo;s sure as hell causing issues with stuff I&amp;rsquo;m copying from my Ubuntu PC.&lt;/p&gt;
&lt;p&gt;Just seems like a dumb idea …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I just found out that HFS+, the preferred file system for Mac OS X, is case-insensitive when it comes to files and directories. I don&amp;rsquo;t understand why? It&amp;rsquo;s sure as hell causing issues with stuff I&amp;rsquo;m copying from my Ubuntu PC.&lt;/p&gt;
&lt;p&gt;Just seems like a dumb idea.&lt;/p&gt;</content><category term="mac"/><category term="osx"/><category term="rant"/></entry><entry><title>Merge video files with mencoder</title><link href="https://davidwinter.dev/2008/05/17/merge-video-files-with-mencoder/" rel="alternate"/><published>2008-05-17T00:00:00+01:00</published><updated>2008-05-17T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-05-17:/2008/05/17/merge-video-files-with-mencoder/</id><content type="html">&lt;p&gt;To merge video files together with &lt;code&gt;mencoder&lt;/code&gt; is simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mencoder -oac copy -ovc copy file1.avi file2.avi file3.avi -o full_movie.avi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="cli"/><category term="mac"/><category term="mencoder"/><category term="ubuntu"/><category term="unix"/></entry><entry><title>Killing a program using a batch file in Windows</title><link href="https://davidwinter.dev/2008/05/15/killing-a-program-using-a-batch-file-in-windows/" rel="alternate"/><published>2008-05-15T00:00:00+01:00</published><updated>2008-05-15T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-05-15:/2008/05/15/killing-a-program-using-a-batch-file-in-windows/</id><summary type="html">&lt;p&gt;Having got my &lt;a href="/2008/05/15/using-shortcut-keys-in-windows/"&gt;keyboard shortcut working&lt;/a&gt; to launch my batch file, next was to actually make it quit the emulator program when invoked.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;@echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;off&lt;/span&gt;
&lt;span class="n"&gt;taskkill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Fusion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is basically the command prompt version of &lt;kbd&gt;CTRL + ALT + DEL&lt;/kbd&gt;. &lt;code&gt;/im&lt;/code&gt; stands for &amp;lsquo;Image Name&amp;rsquo;, which is basically the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Having got my &lt;a href="/2008/05/15/using-shortcut-keys-in-windows/"&gt;keyboard shortcut working&lt;/a&gt; to launch my batch file, next was to actually make it quit the emulator program when invoked.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;@echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;off&lt;/span&gt;
&lt;span class="n"&gt;taskkill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Fusion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is basically the command prompt version of &lt;kbd&gt;CTRL + ALT + DEL&lt;/kbd&gt;. &lt;code&gt;/im&lt;/code&gt; stands for &amp;lsquo;Image Name&amp;rsquo;, which is basically the program executable, and is the same as what you&amp;rsquo;d see in the &amp;lsquo;Task Manager&amp;rsquo; window. &lt;code&gt;/F&lt;/code&gt; just forces the program to close.&lt;/p&gt;</content><category term="batch-file"/><category term="command-prompt"/><category term="windows"/></entry><entry><title>Using shortcut keys in Windows</title><link href="https://davidwinter.dev/2008/05/15/using-shortcut-keys-in-windows/" rel="alternate"/><published>2008-05-15T00:00:00+01:00</published><updated>2008-05-15T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-05-15:/2008/05/15/using-shortcut-keys-in-windows/</id><summary type="html">&lt;p&gt;You won&amp;rsquo;t find me writing about Windows too much on here I promise. I&amp;rsquo;ve been forced to use Windows XP on my arcade machine due to the lack of a decent Sega Mega Drive (Genesis for anyone in the US) emulator on Linux. That has caused other problems …&lt;/p&gt;</summary><content type="html">&lt;p&gt;You won&amp;rsquo;t find me writing about Windows too much on here I promise. I&amp;rsquo;ve been forced to use Windows XP on my arcade machine due to the lack of a decent Sega Mega Drive (Genesis for anyone in the US) emulator on Linux. That has caused other problems though, because the &lt;a href="http://www.emulator-zone.com/doc.php/genesis/fusion.html"&gt;Fusion emulator&lt;/a&gt; doesn&amp;rsquo;t allow me to specify a keyboard combination to quit the program via the keyboard. You may be wondering, &amp;lsquo;Why not just hit &lt;kbd&gt;Alt + F4&lt;/kbd&gt;?&amp;rsquo; Because I&amp;rsquo;m hoping not to have a keyboard plugged in all the time, and just use the joystick and buttons (which are mapped to specific keyboard keys).&lt;/p&gt;
&lt;p&gt;I was going to try and be clever and modify my Python program to intercept a global hot key combination, and then kill the emulator, but thankfully stumbled across the idea of using a Windows shortcut with a shortcut key (the terminology gets quite confusing). The shortcut would be linked to a batch file that would quit the program.&lt;/p&gt;
&lt;p&gt;To cut a long story short (which involved Googling&amp;hellip; a lot), shortcut keys can only be used when the shortcut is &lt;a href="http://support.microsoft.com/kb/134552/en-us"&gt;located in either the Start menu or on the Desktop&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When I launch the shortcut when the emulator isn&amp;rsquo;t running, it opens instantly. I&amp;rsquo;ve noticed however, roughly a 15 second delay for the shortcut to invoke if the emulator is running. I&amp;rsquo;m guessing that this may be something to do with the event buffer in Windows, and the emulator taking up a chunk of the CPU. Though I&amp;rsquo;m just guessing. If anyone knows a fix for that, I&amp;rsquo;d love to hear from you.&lt;/p&gt;</content><category term="windows"/></entry><entry><title>vim: find, comment, save and quit</title><link href="https://davidwinter.dev/2008/02/29/vim-find-comment-save-and-quit/" rel="alternate"/><published>2008-02-29T00:00:00+00:00</published><updated>2008-02-29T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-02-29:/2008/02/29/vim-find-comment-save-and-quit/</id><summary type="html">&lt;p&gt;For the last month, I&amp;rsquo;ve been teaching myself &lt;code&gt;vim&lt;/code&gt;. So here&amp;rsquo;s an explanation for anyone interested in the commands I have been using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/fd0
I
#
&amp;lt;esc&amp;gt;
:wq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Upon opening the file, I used the &lt;code&gt;/&lt;/code&gt; command to search for &amp;lsquo;fd0&amp;rsquo; in the file. In command mode, you just type …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For the last month, I&amp;rsquo;ve been teaching myself &lt;code&gt;vim&lt;/code&gt;. So here&amp;rsquo;s an explanation for anyone interested in the commands I have been using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/fd0
I
#
&amp;lt;esc&amp;gt;
:wq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Upon opening the file, I used the &lt;code&gt;/&lt;/code&gt; command to search for &amp;lsquo;fd0&amp;rsquo; in the file. In command mode, you just type a forward slash, and then the characters to search for straight after it. Hit enter, and it&amp;rsquo;ll give you the first result.&lt;/p&gt;
&lt;p&gt;Next up, I want to insert a comment on that line. Because searching left me a few characters from the start of the line&amp;ndash;where I want to have the comment&amp;ndash;I enter &lt;em&gt;insert&lt;/em&gt; mode with a capital &lt;code&gt;I&lt;/code&gt;. This puts the cursor at the start of the current line. I then put in my &lt;code&gt;#&lt;/code&gt; to comment the line, hit escape to get me back to command mode and then saved and quit the file with &lt;code&gt;:wq&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m finding vim a lot friendlier to work with than emacs. It&amp;rsquo;s not quite TextMate yet, but I&amp;rsquo;m finding it rewarding learning all these different commands.&lt;/p&gt;</content><category term="gvim"/><category term="tips"/><category term="vim"/></entry><entry><title>Me TV - EyeTV for Ubuntu?</title><link href="https://davidwinter.dev/2008/02/10/me-tv-eyetv-for-ubuntu/" rel="alternate"/><published>2008-02-10T00:00:00+00:00</published><updated>2008-02-10T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-02-10:/2008/02/10/me-tv-eyetv-for-ubuntu/</id><summary type="html">&lt;p&gt;My search for an open source, Ubuntu alternative for EyeTV on OS X is nearly over. I stumbled across &amp;lsquo;&lt;a href="http://me-tv.sourceforge.net/index.html"&gt;Me TV&lt;/a&gt;&amp;rsquo; a few days ago&amp;ndash;and I&amp;rsquo;ve left it as long before writing up a post about it so that I could have a good play with it.&lt;/p&gt;
&lt;h2&gt;Installation …&lt;/h2&gt;</summary><content type="html">&lt;p&gt;My search for an open source, Ubuntu alternative for EyeTV on OS X is nearly over. I stumbled across &amp;lsquo;&lt;a href="http://me-tv.sourceforge.net/index.html"&gt;Me TV&lt;/a&gt;&amp;rsquo; a few days ago&amp;ndash;and I&amp;rsquo;ve left it as long before writing up a post about it so that I could have a good play with it.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;For those using Gutsy, you&amp;rsquo;ll need to add the Launchpad repository to your Apt sources:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/apt/sources.list
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add the following to the bottom of the file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;# Me TV&lt;/span&gt;
&lt;span class="k"&gt;deb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://ppa.launchpad.net/michael-lamothe/ubuntu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;gutsy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;deb-src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://ppa.launchpad.net/michael-lamothe/ubuntu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;gutsy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file, and then:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install me-tv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;del datetime="20080211"&gt;If you&amp;rsquo;re running Hardy, Me TV is in the Universal repository, so you can just run &lt;code&gt;sudo apt-get install me-tv&lt;/code&gt;.&lt;/del&gt; &lt;ins datetime="20080211"&gt;&lt;strong&gt;Update:&lt;/strong&gt; After contacting Michael, the developer of Me TV, he&amp;rsquo;s said that the package in the Hardy Universe repository is out of date. For the time being, you&amp;rsquo;re better off adding the LaunchPad repository, as above.&lt;/ins&gt;&lt;/p&gt;
&lt;h2&gt;Features&lt;/h2&gt;
&lt;p&gt;Just a reminder of the features that I&amp;rsquo;m looking for in an application to replace EyeTV:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Watch all Freeview (DVB-T) channels.&lt;/li&gt;
&lt;li&gt;Be able to pause, rewind, and forward up to live TV.&lt;/li&gt;
&lt;li&gt;Schedule programs to record.&lt;/li&gt;
&lt;li&gt;See the TV listings for the channels I have (EPG)&lt;/li&gt;
&lt;li&gt;Fullscreen or windowed viewing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Out of all of the above, there is only one feature&amp;ndash;&amp;lsquo;Be able to pause, rewind, and forward to live TV&amp;rsquo;&amp;ndash;that isn&amp;rsquo;t currently available with Me TV, though I believe it should be possible to implement it in the future with developer support.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a brief run down of those features:&lt;/p&gt;
&lt;h3&gt;Watch all Freeview (DVB-T) channels&lt;/h3&gt;
&lt;p&gt;When you first launch the app, it asks if you would like it to create a &lt;code&gt;channels.conf&lt;/code&gt; file, and then scans for the channels it can find.&lt;/p&gt;
&lt;p&gt;Once this small step is complete, the main window opens with one of the channels on. You&amp;rsquo;ll also notice below the EPG. You can switch channels by scrolling up and down the EPG and clicking on the channel name.&lt;/p&gt;
&lt;h3&gt;Schedule Programs to Record&lt;/h3&gt;
&lt;p&gt;This is as simple as finding the program in the EPG, clicking on Record and then accepting the recording schedule. You can also set, if you want, Me TV to repeat the schedule, say; daily, weekly, etc.&lt;/p&gt;
&lt;h3&gt;Electronic Program Guide - EPG&lt;/h3&gt;
&lt;p&gt;This can be toggled on or off by right clicking in the window. You can scan through the listings every 3 hours, and switch back to what is currently on.&lt;/p&gt;
&lt;h3&gt;Full Screened or Windowed Viewing&lt;/h3&gt;
&lt;p&gt;Simply double click in the main window. Voila.&lt;/p&gt;
&lt;h2&gt;Some Suggestions&lt;/h2&gt;
&lt;p&gt;Me TV is already very user friendly, however, there are a few small things that I think could be altered or added that would make the experience even better:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On the initial launch, rather than asking if Me TV should create a &lt;code&gt;channels.conf&lt;/code&gt; file, instead why not just a notification such as; &amp;lsquo;Me TV needs to scan for channels that you can watch.&amp;rsquo; Non-technical users may get intimidated by the question about a &lt;code&gt;channels.conf&lt;/code&gt; file. Me TV &lt;em&gt;has&lt;/em&gt; to scan for channels. Just let the user know that&amp;rsquo;s what it&amp;rsquo;s doing.&lt;/li&gt;
&lt;li&gt;For the region selection, include a drop down box for the various countries, and then display the regions for that selected country below&amp;ndash;minus the country prefix.&lt;/li&gt;
&lt;li&gt;Ditch the &amp;lsquo;Found Channel&amp;rsquo; text when scanning for channels. Just show the channel name that has been found.&lt;/li&gt;
&lt;li&gt;Move the EPG into it&amp;rsquo;s own window. It always seems as though the TV and EPG are competing against eachother. You always have to resize the window so that you can drag the EPG sizer up so that you can get a good glance at what is on across the channels. Then, when you close the EPG, the TV window is perhaps too big for viewing, so you then have to shrink the window again.&lt;/li&gt;
&lt;li&gt;By moving the EPG into it&amp;rsquo;s own window, it doesn&amp;rsquo;t have to be restricted by the size of the TV window that you want. Users can make it larger, and therefore, rather than sticking to the 3 hour step between programs, why not just include a full 12/24 hours. At the top of the EPG window, have a button to skip by day. You can see a lot more of what&amp;rsquo;s on in one glance with a larger window, than having to scroll around with a smaller one.&lt;/li&gt;
&lt;li&gt;When recording a program from the EPG, after clicking the Record button, don&amp;rsquo;t show the detailed schedule window afterwards. In most cases, I would bet that the user doesn&amp;rsquo;t need to see or change the details. And if they do, they can go to the scheduler to do that. You only really need the details if you&amp;rsquo;re manually creating a recording, or want to set a repeat.&lt;/li&gt;
&lt;li&gt;For quick channel change, perhaps include a drop down box at either the top or bottom of the TV window. This removes the dependancy on switching to the EPG to switch channels, as you currently have to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of these are very small, or rather picky suggestions, but none-the-less more user friendly.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall, Me TV is an &lt;strong&gt;excellent&lt;/strong&gt; application. Obviosuly a lot of time has gone into developing it. If the feature set remained as it was, I would use it from now on, though I believe there are a few things that would make it an &amp;lsquo;easier&amp;rsquo; experience for the user. And the one feature missing that would make it the best ever in Linux, and, hands down, the EyeTV alternative for OS X converts to Ubuntu, would be pause, rewind and forward to live TV.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll be suggesting Me TV to all that I know from now on!&lt;/p&gt;</content><category term="eyetv"/><category term="freeview"/><category term="mac"/><category term="me-tv"/><category term="switch"/><category term="tv"/><category term="ubuntu"/></entry><entry><title>DVB and Mplayer</title><link href="https://davidwinter.dev/2008/02/09/dvb-and-mplayer/" rel="alternate"/><published>2008-02-09T00:00:00+00:00</published><updated>2008-02-09T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-02-09:/2008/02/09/dvb-and-mplayer/</id><summary type="html">&lt;p&gt;As a follow up to &lt;a href="/2008/02/08/watching-freeview-dvb-t-tv-with-vlc-player-on-ubuntu/"&gt;yesterday&amp;rsquo;s post&lt;/a&gt;, here is a quick run through of how to use &lt;a href="http://www.mplayerhq.hu/design7/news.html"&gt;Mplayer&lt;/a&gt; to view DVB channels.&lt;/p&gt;
&lt;p&gt;Basically, you just need to generate a &lt;code&gt;channels.conf&lt;/code&gt; file (&lt;a href="/2008/02/08/watching-freeview-dvb-t-tv-with-vlc-player-on-ubuntu/"&gt;see this article&lt;/a&gt;) and place it inside &lt;code&gt;~/.mplayer/&lt;/code&gt;. Then run &lt;code&gt;mplayer dvb://&lt;/code&gt; in a terminal window. You …&lt;/p&gt;</summary><content type="html">&lt;p&gt;As a follow up to &lt;a href="/2008/02/08/watching-freeview-dvb-t-tv-with-vlc-player-on-ubuntu/"&gt;yesterday&amp;rsquo;s post&lt;/a&gt;, here is a quick run through of how to use &lt;a href="http://www.mplayerhq.hu/design7/news.html"&gt;Mplayer&lt;/a&gt; to view DVB channels.&lt;/p&gt;
&lt;p&gt;Basically, you just need to generate a &lt;code&gt;channels.conf&lt;/code&gt; file (&lt;a href="/2008/02/08/watching-freeview-dvb-t-tv-with-vlc-player-on-ubuntu/"&gt;see this article&lt;/a&gt;) and place it inside &lt;code&gt;~/.mplayer/&lt;/code&gt;. Then run &lt;code&gt;mplayer dvb://&lt;/code&gt; in a terminal window. You&amp;rsquo;ll get a video window appear, and the first channel within your &lt;code&gt;channels.conf&lt;/code&gt; file will start playing. To switch up and down between channels, you can press &lt;strong&gt;h&lt;/strong&gt; and &lt;strong&gt;k&lt;/strong&gt;. There&amp;rsquo;s a &lt;a href="http://www.keyxl.com/aaa2fa5/302/MPlayer-keyboard-shortcuts.htm"&gt;bunch of other helpful keyboard commands&lt;/a&gt; though not all of them will work with DVB.&lt;/p&gt;
&lt;p&gt;While using Mplayer this way isn&amp;rsquo;t very user friendly, it may be helpful for some.&lt;/p&gt;</content><category term="freeview"/><category term="howto"/><category term="mplayer"/><category term="tv"/><category term="ubuntu"/></entry><entry><title>Watching Freeview (DVB-T) TV with VLC Player on Ubuntu</title><link href="https://davidwinter.dev/2008/02/08/watching-freeview-dvb-t-tv-with-vlc-player-on-ubuntu/" rel="alternate"/><published>2008-02-08T00:00:00+00:00</published><updated>2008-02-08T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2008-02-08:/2008/02/08/watching-freeview-dvb-t-tv-with-vlc-player-on-ubuntu/</id><summary type="html">&lt;p&gt;Watching TV on my desktop. What do I want to be able to do?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Watch all &lt;a href="http://www.freeview.co.uk/home"&gt;Freeview&lt;/a&gt; (DVB-T) channels.&lt;/li&gt;
&lt;li&gt;Be able to pause, rewind, and forward to live TV.&lt;/li&gt;
&lt;li&gt;Schedule programs to record.&lt;/li&gt;
&lt;li&gt;See the TV listings for the channels I have.&lt;/li&gt;
&lt;li&gt;Fullscreen or windowed viewing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was able to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Watching TV on my desktop. What do I want to be able to do?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Watch all &lt;a href="http://www.freeview.co.uk/home"&gt;Freeview&lt;/a&gt; (DVB-T) channels.&lt;/li&gt;
&lt;li&gt;Be able to pause, rewind, and forward to live TV.&lt;/li&gt;
&lt;li&gt;Schedule programs to record.&lt;/li&gt;
&lt;li&gt;See the TV listings for the channels I have.&lt;/li&gt;
&lt;li&gt;Fullscreen or windowed viewing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was able to do all of the above using &lt;a href="http://www.elgato.com/elgato/int/mainmenu/home.en.html"&gt;EyeTV&lt;/a&gt; on my Mac. However, I&amp;rsquo;m trying to make the complete switch to &lt;a href="http://www.ubuntu.com"&gt;Ubuntu&lt;/a&gt;, and an open-source alternative is needed.&lt;/p&gt;
&lt;p&gt;I initially setup &lt;a href="http://www.mythtv.org/"&gt;MythTV&lt;/a&gt;. It consists of two parts, a server and a client. Multiple clients around the home (or over the internet) can connect to the server. That was a little over-the-top for my needs, but MythTV is a very popular choice for TV on Linux, and does do most of the things I want from the list above, hence my decision to use it.&lt;/p&gt;
&lt;p&gt;Once installed, I had TV playing perfectly. Though, when I wanted to start doing some work, while still watching TV, it was a little annoying that I couldn&amp;rsquo;t find anyway of watching the TV in a window&amp;ndash;only fullscreen. Trying to find a solution on IRC, some users said there was an option to play TV in a window, however, when I tried to enable the option numerous times, I had no luck.&lt;/p&gt;
&lt;p&gt;At this point I thought that my journey to Ubuntu was over. I needed TV on my computer, and if I couldn&amp;rsquo;t watch it in a window while doing other things, then I&amp;rsquo;d have to keep my Mac around to do that.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not too sure how I stumbled across it, but I found a web page explaining that you could use &lt;a href="http://www.videolan.org/vlc/"&gt;VLC Player&lt;/a&gt; to tune into a TV card! And since then, for the last few hours, I&amp;rsquo;ve been working on getting that working. At the moment, it only ticks off a few of the boxes, but I&amp;rsquo;m sure, with a bit more Googling, I&amp;rsquo;ll be able to get the other things functioning. With the following, I can watch all my Freeview channels, in full screen or in a window.&lt;/p&gt;
&lt;h2&gt;Setting it all up&lt;/h2&gt;
&lt;p&gt;Assuming that you have your TV card drivers installed, you can start off with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install dvb-utils vlc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That installs VLC and the DVB programs needed to scan for your channels.&lt;/p&gt;
&lt;p&gt;Now, find the digital transmitter nearest to you by visiting &lt;a href="http://www.digitaluk.co.uk/postcodechecker/"&gt;DigitalUK&lt;/a&gt;. Enter in your postcode, and the result you get back will tell you which transmitter you&amp;rsquo;re feeding off of. If you&amp;rsquo;re not in the UK, I&amp;rsquo;m not sure how you can find your closest one&amp;ndash;&lt;a href="http://google.com"&gt;Google&lt;/a&gt; is your friend.&lt;/p&gt;
&lt;p&gt;You can see a list of the UK transmitters by doing:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ls /usr/share/doc/dvb-utils/examples/scan/dvb-t/ | grep uk-
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now find the filename that matches your transmitter, and substitute &lt;code&gt;uk-CrystalPalace&lt;/code&gt; for it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;scan /usr/share/doc/dvb-utils/examples/scan/dvb-t/uk-CrystalPalace -o zap | tee ~/channels.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above command will scan for channels that your TV card can pick-up, and store the configuration in a file. This file VLC then uses to tune in.&lt;/p&gt;
&lt;p&gt;Now open up VLC. &lt;strong&gt;File&lt;/strong&gt; &amp;gt; &lt;strong&gt;Quick Open File&lt;/strong&gt;. Browse to &lt;code&gt;channels.conf&lt;/code&gt; and open. Live TV should now start playing. To see a list of channels to switch between, go to &lt;strong&gt;View&lt;/strong&gt; &amp;gt; &lt;strong&gt;Playlist&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To speed things up when wanting to launch the TV each time, you can create a launcher. I&amp;rsquo;ll create it on the Desktop for examples sake. Right click, and select &lt;strong&gt;Create Launcher&lt;/strong&gt;. Give it a name, like TV, and in the Command text box, enter &lt;code&gt;vlc /path/to/channels.conf&lt;/code&gt;. Hit ok, and you&amp;rsquo;re done. Now double click on the launcher and VLC will launch, and you&amp;rsquo;ll have the TV back on.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it! Now all that is left for me to do, is to see if there is a way I can get the other things on my list operational; pause, schedule, tv listings. I&amp;rsquo;ll report back on here with any developments I find. Tune in again next week for more exciting adventures with Ubuntu!&lt;/p&gt;
&lt;p&gt;What TV app do you use on Ubuntu?&lt;/p&gt;</content><category term="freeview"/><category term="howto"/><category term="tv"/><category term="ubuntu"/><category term="vlc"/></entry><entry><title>Line breaks in OpenOffice.org</title><link href="https://davidwinter.dev/2007/05/21/line-breaks-in-openofficeorg/" rel="alternate"/><published>2007-05-21T00:00:00+01:00</published><updated>2007-05-21T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2007-05-21:/2007/05/21/line-breaks-in-openofficeorg/</id><summary type="html">&lt;p&gt;A really frustrating issue I had when writing my project report, was that of dealing with source code formatting.&lt;/p&gt;
&lt;p&gt;I had created a new style for source code similar to that I use on my blog; a box with a border and coloured background. The problem I was having was …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A really frustrating issue I had when writing my project report, was that of dealing with source code formatting.&lt;/p&gt;
&lt;p&gt;I had created a new style for source code similar to that I use on my blog; a box with a border and coloured background. The problem I was having was when pasting source code into the document. Each line had a &lt;em&gt;paragraph&lt;/em&gt; break between itself and the next, which meant that there was a spacing between each. To fix this, I had to insert a manual &lt;em&gt;line&lt;/em&gt; break between each line. Luckily I found a shortcut to pull this off, which was &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Does anyone know of an easier way of pasting in text and using line breaks rather than paragraph breaks?&lt;/p&gt;</content><category term="openofficeorg"/><category term="uni"/></entry><entry><title>mod_rewrite and Mac OS X Personal Web Sharing</title><link href="https://davidwinter.dev/2007/05/20/mod_rewrite-and-mac-os-x-personal-web-sharing/" rel="alternate"/><published>2007-05-20T00:00:00+01:00</published><updated>2007-05-20T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2007-05-20:/2007/05/20/mod_rewrite-and-mac-os-x-personal-web-sharing/</id><summary type="html">&lt;p&gt;It was very frustrating installing a fresh &lt;a href="http://www.wordpress.org"&gt;Wordpress&lt;/a&gt; on my Mac and finding that the permalinks didn&amp;rsquo;t work. Turns out the default Apache settings for personal web sharing on OS X disable &lt;code&gt;.htaccess&lt;/code&gt; overriding.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo mate /etc/httpd/users/yourusername.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you&amp;rsquo;ll want to enable Apache to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;It was very frustrating installing a fresh &lt;a href="http://www.wordpress.org"&gt;Wordpress&lt;/a&gt; on my Mac and finding that the permalinks didn&amp;rsquo;t work. Turns out the default Apache settings for personal web sharing on OS X disable &lt;code&gt;.htaccess&lt;/code&gt; overriding.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo mate /etc/httpd/users/yourusername.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you&amp;rsquo;ll want to enable Apache to follow symbolic links:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Options Indexes MultiViews FollowSymLinks
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And to allow &lt;code&gt;.htaccess&lt;/code&gt; overriding:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;AllowOverride All
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The file should then look like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;quot;/Users/yourusername/Sites/&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Options&lt;span class="w"&gt; &lt;/span&gt;Indexes&lt;span class="w"&gt; &lt;/span&gt;MultiViews&lt;span class="w"&gt; &lt;/span&gt;FollowSymLinks
&lt;span class="w"&gt;    &lt;/span&gt;AllowOverride&lt;span class="w"&gt; &lt;/span&gt;All
&lt;span class="w"&gt;    &lt;/span&gt;Order&lt;span class="w"&gt; &lt;/span&gt;allow,deny
&lt;span class="w"&gt;    &lt;/span&gt;Allow&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;all
&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now in System Preferences, stop and start &amp;lsquo;Personal Web Sharing&amp;rsquo;. Things should work perfectly now.&lt;/p&gt;</content><category term="apache"/><category term="howto"/><category term="mac"/><category term="wordpress"/></entry><entry><title>Graphviz - for drawing directed graphs</title><link href="https://davidwinter.dev/2007/03/14/graphviz-for-drawing-directed-graphs/" rel="alternate"/><published>2007-03-14T00:00:00+00:00</published><updated>2007-03-14T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2007-03-14:/2007/03/14/graphviz-for-drawing-directed-graphs/</id><summary type="html">&lt;p&gt;This semester at University, I&amp;rsquo;m taking &amp;lsquo;Compiler Design &amp;amp; Techniques&amp;rsquo; as a module. The second coursework involves drawing &lt;a href="http://en.wikipedia.org/wiki/Finite_state_machines"&gt;Finite State Machines&lt;/a&gt; diagrams that represent regular expressions. Rather than using a word processor to draw these diagrams with a rather untidy look about them, I went in search of a tool …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This semester at University, I&amp;rsquo;m taking &amp;lsquo;Compiler Design &amp;amp; Techniques&amp;rsquo; as a module. The second coursework involves drawing &lt;a href="http://en.wikipedia.org/wiki/Finite_state_machines"&gt;Finite State Machines&lt;/a&gt; diagrams that represent regular expressions. Rather than using a word processor to draw these diagrams with a rather untidy look about them, I went in search of a tool that&amp;rsquo;d help me produce high quality drawings. I&amp;rsquo;d heard that Latex was good for mathematical diagrams, but that seemed like overkill as I only wanted the diagrams, not a whole new document syntax to learn.&lt;/p&gt;
&lt;p&gt;I come across &lt;a href="http://www.graphviz.org/"&gt;Graphviz&lt;/a&gt;. Open source and available on near enough all platforms&amp;ndash;&lt;a href="http://www.ryandesign.com/graphviz/"&gt;Mac&lt;/a&gt;, &lt;a href="http://www.graphviz.org/Download_linux.php"&gt;Linux&lt;/a&gt; and &lt;a href="http://www.graphviz.org/Download_windows.php"&gt;Windows&lt;/a&gt;. Using a very simple syntax, you create &lt;code&gt;dot&lt;/code&gt; files and then using the &lt;code&gt;dot&lt;/code&gt; tool, you can generate PNG images of your diagrams.&lt;/p&gt;
&lt;p&gt;Here is an example &lt;code&gt;dot&lt;/code&gt; script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;digraph my_fsm {
    label = &amp;quot;ab*(cd)+|b&amp;quot;;
    rankdir = LR;
    node [shape = doublecircle]; 3 4;
    node [shape = circle];
    0 -&amp;gt; 1 [label = &amp;quot;a&amp;quot;];
    1 -&amp;gt; 1 [label = &amp;quot;b&amp;quot;];
    1 -&amp;gt; 2 [label = &amp;quot;c&amp;quot;];
    2 -&amp;gt; 3 [label = &amp;quot;d&amp;quot;];
    3 -&amp;gt; 2 [label = &amp;quot;c&amp;quot;];
    0 -&amp;gt; 4 [label = &amp;quot;b&amp;quot;];
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Following is an explanation of the above script:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I&amp;rsquo;m declaring the graph as a directed graph with &lt;code&gt;digraph&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;my_fsm&lt;/code&gt; is just the name I&amp;rsquo;ve given the graph. This can be anything.&lt;/li&gt;
&lt;li&gt;I add a label to the graph which holds the regular expression that I&amp;rsquo;m drawing. This isn&amp;rsquo;t required, but just helps by giving it a title.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rankdir&lt;/code&gt; specifies the direction of the diagram. I&amp;rsquo;m specifying &amp;lsquo;left to right&amp;rsquo; with &lt;code&gt;LR&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;So that I can differentiate between accepting states and normal states, I&amp;rsquo;m declaring that nodes 3 and 4 will have a double circle around them.&lt;/li&gt;
&lt;li&gt;For all other nodes, I just want to use the normal &lt;code&gt;circle&lt;/code&gt; shape.&lt;/li&gt;
&lt;li&gt;Lastly, I declare the nodes and their edges. Also, I add a label to each edge.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you save the file, you can run it through the &lt;code&gt;dot&lt;/code&gt; program using the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;dot my_file.dot -Tpng -o my_fsm.png
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll need to check where &lt;code&gt;dot&lt;/code&gt; was installed. With the Mac installer package it is installed to &lt;code&gt;/usr/local/graphviz-2.12/bin/dot&lt;/code&gt;, so you&amp;rsquo;ll need to modify the above command to reflect the correct location.&lt;/p&gt;
&lt;p&gt;A very handy tool indeed. There is a &lt;a href="http://www.graphviz.org/Documentation/dotguide.pdf"&gt;PDF guide&lt;/a&gt; on all the commands available. Of which, I&amp;rsquo;m next going to look for how to space the graph out a bit more as it&amp;rsquo;s a little squashed at the moment.&lt;/p&gt;
&lt;p&gt;Hope this helps.&lt;/p&gt;</content><category term="apps"/><category term="drawing"/><category term="mac"/><category term="uni"/><category term="unix"/></entry><entry><title>Switch to Static IP on Ubuntu Server</title><link href="https://davidwinter.dev/2007/01/27/switch-to-static-ip-on-ubuntu-server/" rel="alternate"/><published>2007-01-27T00:00:00+00:00</published><updated>2007-01-27T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2007-01-27:/2007/01/27/switch-to-static-ip-on-ubuntu-server/</id><summary type="html">&lt;p&gt;I just bought a new Linksys router for my home network and wanted to set-up my Ubuntu Web Server with a static IP address so that I could port-forward a few things. Trouble is, with only the command line it&amp;rsquo;s a little tricky to figure out exactly how to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I just bought a new Linksys router for my home network and wanted to set-up my Ubuntu Web Server with a static IP address so that I could port-forward a few things. Trouble is, with only the command line it&amp;rsquo;s a little tricky to figure out exactly how to do it. Following are the steps I used.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/network/interfaces
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside the file, you&amp;rsquo;ll see the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;iface eth1 inet dhcp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We want to switch from &lt;code&gt;dhcp&lt;/code&gt; to a &lt;code&gt;static&lt;/code&gt; IP address. Comment or delete that line, and then add the following to the file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;iface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eth1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;static&lt;/span&gt;
&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m m-Double"&gt;192.168.1.200&lt;/span&gt;
&lt;span class="nx"&gt;netmask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m m-Double"&gt;255.255.255.0&lt;/span&gt;
&lt;span class="nx"&gt;gateway&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m m-Double"&gt;192.168.1.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;This line states we want to use a static IP address.&lt;/li&gt;
&lt;li&gt;The static IP address you want to use.&lt;/li&gt;
&lt;li&gt;The subnet mask.&lt;/li&gt;
&lt;li&gt;This is the IP address of my router which connects to the Internet.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Save the file and then restart the network settings:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/networking restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Job done.&lt;/p&gt;</content><category term="command-line"/><category term="home"/><category term="howto"/><category term="linux"/><category term="ubuntu"/></entry><entry><title>Unix Disk Usage</title><link href="https://davidwinter.dev/2007/01/21/unix-disk-usage/" rel="alternate"/><published>2007-01-21T00:00:00+00:00</published><updated>2007-01-21T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2007-01-21:/2007/01/21/unix-disk-usage/</id><summary type="html">&lt;p&gt;A very handy command to see the total size of a directory on a Unix-based computer.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;du -sh *
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will show the total size of files and directories in your current working directory. The &lt;code&gt;s&lt;/code&gt; flag means to show a summary&amp;ndash;which basically just shows the top level directory only …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A very handy command to see the total size of a directory on a Unix-based computer.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;du -sh *
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will show the total size of files and directories in your current working directory. The &lt;code&gt;s&lt;/code&gt; flag means to show a summary&amp;ndash;which basically just shows the top level directory only, instead of the contents of each and every folder down the file system hierarchy. The &lt;code&gt;h&lt;/code&gt; flag shows a human readable file size.&lt;/p&gt;
&lt;p&gt;For my home directory, I get the following output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;404&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Desktop&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;30&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Documents&lt;/span&gt;
&lt;span class="mf"&gt;6.0&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Library&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;32&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Movies&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;18&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Music&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;11&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Pictures&lt;/span&gt;
&lt;span class="mf"&gt;2.7&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Projects&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;16&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Public&lt;/span&gt;
&lt;span class="mf"&gt;166&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Sites&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="command-line"/><category term="dapper"/><category term="freebsd"/><category term="howto"/><category term="ubuntu"/><category term="unix"/></entry><entry><title>Mac "Hot Corners" for Ubuntu</title><link href="https://davidwinter.dev/2006/12/29/mac-hot-corners-for-ubuntu/" rel="alternate"/><published>2006-12-29T00:00:00+00:00</published><updated>2006-12-29T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-12-29:/2006/12/29/mac-hot-corners-for-ubuntu/</id><summary type="html">&lt;p&gt;I&amp;rsquo;ve had a bit more time recently to play around with Ubuntu and am finding the &amp;lsquo;Ubuntu versions&amp;rsquo; of apps that I&amp;rsquo;ve grown to love on Mac OS X. One of which being Hot Corners which I always use to lock my screen when moving away from it …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;ve had a bit more time recently to play around with Ubuntu and am finding the &amp;lsquo;Ubuntu versions&amp;rsquo; of apps that I&amp;rsquo;ve grown to love on Mac OS X. One of which being Hot Corners which I always use to lock my screen when moving away from it.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://packages.ubuntulinux.org/dapper/gnome/brightside"&gt;Brightside&lt;/a&gt; is the Ubuntu app to do the job.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install brightside
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once installed, go to System, Preferences, Screen Actions. I then checked the &amp;ldquo;Bottom right corner&amp;rdquo; and then chose &amp;ldquo;Start screensaver&amp;rdquo;. Works a charm.&lt;/p&gt;
&lt;p&gt;Be sure that in your Screensaver settings to check the &amp;ldquo;Lock screen when screensaver is active&amp;rdquo; option.&lt;/p&gt;</content><category term="apps"/><category term="mac"/><category term="ubuntu"/></entry><entry><title>Festive Mac Screen Saver</title><link href="https://davidwinter.dev/2006/12/17/festive-mac-screen-saver/" rel="alternate"/><published>2006-12-17T00:00:00+00:00</published><updated>2006-12-17T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-12-17:/2006/12/17/festive-mac-screen-saver/</id><content type="html">&lt;p&gt;Here&amp;rsquo;s a great Mac screen saver to get you in the Christmas spirit&amp;ndash;&lt;a href="http://wakaba.c3.cx/s/lotsablankers/lotsasnow.html"&gt;LotsaSnow&lt;/a&gt;. It generates unique snow flakes that then gently fall down from the top of your screen. It&amp;rsquo;s very customisable and it&amp;rsquo;s a Universal binary.&lt;/p&gt;</content><category term="christmas"/><category term="mac"/></entry><entry><title>Change your Terminal prompt - Lost style</title><link href="https://davidwinter.dev/2006/12/06/change-your-terminal-prompt-lost-style/" rel="alternate"/><published>2006-12-06T00:00:00+00:00</published><updated>2006-12-06T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-12-06:/2006/12/06/change-your-terminal-prompt-lost-style/</id><summary type="html">&lt;p&gt;Fancy a change from the default prompt you get in your Terminal? Want to mimic the Terminal prompt used in &lt;a href="http://abc.go.com/primetime/lost/index"&gt;Lost&lt;/a&gt;? I did, and during a boring lecture at Uni, decided to update it.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using &lt;code&gt;zsh&lt;/code&gt; currently, but this will also work for a &lt;code&gt;bash&lt;/code&gt; shell (default with …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Fancy a change from the default prompt you get in your Terminal? Want to mimic the Terminal prompt used in &lt;a href="http://abc.go.com/primetime/lost/index"&gt;Lost&lt;/a&gt;? I did, and during a boring lecture at Uni, decided to update it.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using &lt;code&gt;zsh&lt;/code&gt; currently, but this will also work for a &lt;code&gt;bash&lt;/code&gt; shell (default with Mac OS X). I&amp;rsquo;m using &lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt; to edit my files, but if you&amp;rsquo;re on Linux (&lt;a href="http://www.ubuntu.com"&gt;Ubuntu&lt;/a&gt;, right?), then just substitute the &lt;code&gt;mate&lt;/code&gt; command for &lt;code&gt;nano&lt;/code&gt; or your favourite editor.&lt;/p&gt;
&lt;p&gt;Just to make sure that you&amp;rsquo;re in your home directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ~
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now open your shell profile. If you&amp;rsquo;re using &lt;code&gt;zsh&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mate .zprofile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or if you&amp;rsquo;re using &lt;code&gt;bash&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mate .bashrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now add the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;gt;: &amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save and close the file.&lt;/p&gt;
&lt;p&gt;Now, make sure you have the right colour scheme going on.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;lsquo;Terminal&amp;rsquo; from the main menu.&lt;/li&gt;
&lt;li&gt;Select &amp;lsquo;Window Settings&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Select &amp;lsquo;Color&amp;rsquo; in the drop down&lt;/li&gt;
&lt;li&gt;Select &amp;lsquo;Green on Black&amp;rsquo; from the &amp;lsquo;Standard Color Selections&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Click the big &amp;lsquo;Use Settings as Defaults&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Close the window, and you&amp;rsquo;re done&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Open a new Terminal window and you should get a nice Lost &amp;lsquo;style&amp;rsquo; for your prompt. Nothing too fancy&amp;ndash;just something nice and simple.&lt;/p&gt;
&lt;p&gt;Now, you only have 108 minutes to enter the code&amp;hellip; so don&amp;rsquo;t waste time!&lt;/p&gt;
&lt;p&gt;Damn. I can&amp;rsquo;t wait until the next episode.&lt;/p&gt;</content><category term="command-line"/><category term="lost"/><category term="mac"/><category term="unix"/></entry><entry><title>Getting Ubuntu Dapper to dance with ATI X800 GTO</title><link href="https://davidwinter.dev/2006/10/25/getting-ubuntu-dapper-to-dance-with-ati-x800-gto/" rel="alternate"/><published>2006-10-25T00:00:00+01:00</published><updated>2006-10-25T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-10-25:/2006/10/25/getting-ubuntu-dapper-to-dance-with-ati-x800-gto/</id><summary type="html">&lt;p&gt;I&amp;rsquo;ve made a brand new spare PC that I&amp;rsquo;m hoping my parents can use in their spare room/study. I refuse to install Windows, but as everyone knows, I&amp;rsquo;m a keen Ubuntu fan.&lt;/p&gt;
&lt;p&gt;My younger brother donated me his &amp;ldquo;old&amp;rdquo; ATI Radeon X800 GTO graphics card to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;ve made a brand new spare PC that I&amp;rsquo;m hoping my parents can use in their spare room/study. I refuse to install Windows, but as everyone knows, I&amp;rsquo;m a keen Ubuntu fan.&lt;/p&gt;
&lt;p&gt;My younger brother donated me his &amp;ldquo;old&amp;rdquo; ATI Radeon X800 GTO graphics card to use in it (I want to eventually get XGL + Compiz set-up on it for all the neat eye candy). Thing is, Ubuntu and the card don&amp;rsquo;t play nice straight away. Here&amp;rsquo;s how I got them to dance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This was from a fresh install of Ubuntu Dapper.&lt;/p&gt;
&lt;p&gt;Boot from the Ubuntu install CD and when you&amp;rsquo;re presented with the install options, select &amp;ldquo;Safe Graphics Mode&amp;rdquo;. This will let Ubuntu run using your ATI card and some safe graphics drivers - you only need this so that you can complete the installation.&lt;/p&gt;
&lt;p&gt;When the live CD environment has loaded and you see the desktop, run the &amp;lsquo;Install&amp;rsquo; program from the desktop as-per-normal. Once it&amp;rsquo;s completed it&amp;rsquo;s best to upgrade Dapper to the latest version. You can either do this from the Terminal or via the notification bubble that pops up in the menu bar:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll probably need to reboot once that&amp;rsquo;s done because a new kernel (I&amp;rsquo;m guessing) has been installed. Once you&amp;rsquo;ve rebooted, type in a Terminal window:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;xorg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;fglrx&lt;/span&gt;
&lt;span class="nx"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;aticonfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt;
&lt;span class="nx"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;aticonfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;overlay&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;Xv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This downloads and sets up the ATI proprietary drivers for you.&lt;/p&gt;
&lt;p&gt;Now just restart the window environment by hitting CTRL + ALT + BACKSPACE on your keyboard. The screen will go to a normal command line login type screen for about 30 seconds or less. Then the desktop will appear again. You&amp;rsquo;re now running Ubuntu with the ATI drivers. Bravo!&lt;/p&gt;
&lt;p&gt;This was a must for me as I have bought a a nice 19&amp;rdquo; widescreen flatscreen monitor - and unless I installed the drivers, I couldn&amp;rsquo;t get the nice big resolutions. Now I have a lovely 1440 x 900 res. Lovely jubbly.&lt;/p&gt;</content><category term="dapper"/><category term="howto"/><category term="ubuntu"/></entry><entry><title>Building Apache 2.2 from source for Ubuntu Dapper</title><link href="https://davidwinter.dev/2006/10/17/building-apache-22-from-source-for-ubuntu-dapper/" rel="alternate"/><published>2006-10-17T00:00:00+01:00</published><updated>2006-10-17T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-10-17:/2006/10/17/building-apache-22-from-source-for-ubuntu-dapper/</id><summary type="html">&lt;p&gt;Two reasons you might want to do this.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You want to host a Rails application using Mongrel via Apache and &lt;code&gt;mod_proxy_balancer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;re studying in a Website administration module for your 3rd year Software Engineering degree :)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Seriously though, if you don&amp;rsquo;t want to use &lt;code&gt;mod_proxy_balancer&lt;/code&gt;, just do a normal …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Two reasons you might want to do this.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You want to host a Rails application using Mongrel via Apache and &lt;code&gt;mod_proxy_balancer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;re studying in a Website administration module for your 3rd year Software Engineering degree :)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Seriously though, if you don&amp;rsquo;t want to use &lt;code&gt;mod_proxy_balancer&lt;/code&gt;, just do a normal &lt;code&gt;apt-get install&lt;/code&gt; of Apache 2 and you&amp;rsquo;ll be fine. &lt;code&gt;mod_proxy_balancer&lt;/code&gt; is only available for Apache 2.2, and currently, that&amp;rsquo;s not available from the Ubuntu repositories via &lt;code&gt;apt-get&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This article only covers installing Apache 2.2 - I&amp;rsquo;ll write another one for getting Subversion and PHP working shortly afterwards.&lt;/p&gt;
&lt;h3&gt;Workspace&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;ve not got the &lt;code&gt;build-essential&lt;/code&gt; package installed yet:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install build-essential
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;s best to keep all of the source files in a seperate directory so they don&amp;rsquo;t mess up your home directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd
mkdir src
cd src
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Zlib&lt;/h3&gt;
&lt;p&gt;So that Apache can compress output to browsers that support it, we&amp;rsquo;re going to install Zlib first of all:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;wget http://www.zlib.net/zlib-1.2.3.tar.gz
tar xvfz zlib-1.2.3.tar.gz
cd zlib-1.2.3/
./configure --prefix=/usr/local
make
sudo make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Apache 2.2&lt;/h3&gt;
&lt;p&gt;Now download the Apache 2.2 source files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ..
wget http://apache.rmplc.co.uk/httpd/httpd-2.2.3.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Extract and move into the directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tar xvfz httpd-2.2.3.tar.gz
cd httpd-2.2.3/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now to configure the build of Apache 2.2 that we want:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./configure --prefix=/usr/local/apache2 --enable-mods-shared=all --enable-deflate --enable-proxy --enable-proxy-balancer --enable-proxy-http
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Besides setting the modules we&amp;rsquo;d like installed, and the location of the install, this paramater &lt;code&gt;--enable-mods-shared=all&lt;/code&gt; is telling Apache 2.2 to build modules so that they can be dynamically loaded when it is started. This means, we can add further modules to our Apache 2.2 install when we like - as we will do with the Subversion modules and PHP.&lt;/p&gt;
&lt;p&gt;Once the configuration is complete:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;make
sudo make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;rsquo;s test that it&amp;rsquo;s working:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /usr/local/apache2/bin/apachectl start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now navigate to &lt;a href="http://localhost"&gt;http://localhost&lt;/a&gt; and you should see a message saying &amp;ldquo;It works!&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Stop Apache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /usr/local/apache2/bin/apachectl stop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Apache at start-up&lt;/h3&gt;
&lt;p&gt;Now let&amp;rsquo;s get Apache to start at boot time automatically:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo cp /usr/local/apache2/bin/apachectl /etc/init.d/apachectl
sudo chmod +x /etc/init.d/apachectl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What we&amp;rsquo;re doing here is copying the Apache Control script into the start-up directory.&lt;/p&gt;
&lt;p&gt;We just need to add a few lines to the file for it to work nicely:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/init.d/apachectl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add the followinig, so the top of the file looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# chkconfig: - 85 15&lt;/span&gt;
&lt;span class="c1"&gt;# description: Apache is a web server.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file.&lt;/p&gt;
&lt;p&gt;Now we need to register it with the start-up manager:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /usr/sbin/update-rc.d apachectl defaults
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Securing Apache&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s also a good idea to create a dedicate Apache system user account. It&amp;rsquo;ll make your install much more secure.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo adduser --system apache
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we just need to make sure that Apache runs under this user. We do that by editting the configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /usr/local/apache2/conf/httpd.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You need to find the lines that say:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;User daemon
Group daemon
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And change them so they look like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;User apache
Group nogroup
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s start Apache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /usr/local/apache2/bin/apachectl start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now to check it&amp;rsquo;s running under the new user, &lt;code&gt;apache&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ps -aux | grep httpd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you see the word &lt;code&gt;apache&lt;/code&gt; in there, it&amp;rsquo;s working.&lt;/p&gt;
&lt;h3&gt;Check it&amp;rsquo;s all working&lt;/h3&gt;
&lt;p&gt;Now just reboot the system and before logging in, check on another machine by visiting the servers IP in the web browser and you should see the &amp;ldquo;It works!&amp;rdquo; message. This means Apache started up correctly automatically.&lt;/p&gt;
&lt;p&gt;Building Apache 2.2 from source. Done.&lt;/p&gt;</content><category term="apache"/><category term="dapper"/><category term="howto"/><category term="server"/><category term="source"/><category term="ubuntu"/></entry><entry><title>Subversion 1.4.0 from source via Apache 2.2 on Ubuntu Dapper</title><link href="https://davidwinter.dev/2006/10/17/subversion-140-from-source-over-apache-22-on-ubuntu-dapper/" rel="alternate"/><published>2006-10-17T00:00:00+01:00</published><updated>2006-10-17T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-10-17:/2006/10/17/subversion-140-from-source-over-apache-22-on-ubuntu-dapper/</id><summary type="html">&lt;p&gt;This howto assumes you&amp;rsquo;ve already followed my &lt;a href="/2006/10/17/building-apache-2.2-from-source-for-ubuntu-dapper/"&gt;Building Apache 2.2 from source&lt;/a&gt;  article.&lt;/p&gt;
&lt;p&gt;Now we&amp;rsquo;re going to install Subversion 1.4.0 from source so that it can be access via Apache with authentication.&lt;/p&gt;
&lt;h3&gt;Installing Subversion&lt;/h3&gt;
&lt;p&gt;As we&amp;rsquo;ve built Apache from source, we&amp;rsquo;ll need to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This howto assumes you&amp;rsquo;ve already followed my &lt;a href="/2006/10/17/building-apache-2.2-from-source-for-ubuntu-dapper/"&gt;Building Apache 2.2 from source&lt;/a&gt;  article.&lt;/p&gt;
&lt;p&gt;Now we&amp;rsquo;re going to install Subversion 1.4.0 from source so that it can be access via Apache with authentication.&lt;/p&gt;
&lt;h3&gt;Installing Subversion&lt;/h3&gt;
&lt;p&gt;As we&amp;rsquo;ve built Apache from source, we&amp;rsquo;ll need to do the same for Subversion in order to get the Apache 2 modules &lt;code&gt;mod_dav_svn&lt;/code&gt; and &lt;code&gt;mod_authz_svn&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;subversion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tigris&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;downloads&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;subversion&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="n"&gt;tar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gz&lt;/span&gt;
&lt;span class="n"&gt;tar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xvfz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;subversion&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="n"&gt;tar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gz&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;subversion&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;apxs&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;apache2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;apxs&lt;/span&gt;
&lt;span class="n"&gt;make&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will also add the relevant &lt;code&gt;LoadModule&lt;/code&gt; directives into your Apache 2 configuration for you.&lt;/p&gt;
&lt;h3&gt;Creating your repository&lt;/h3&gt;
&lt;p&gt;Now, create your Subversion repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;svnadmin create /home/yourusername/subversion/repos
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We have to make that repository owned by Apache so that it can be accessed via the web:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo chown -R apache /home/yourusername/subversion/repos
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Authentication File&lt;/h3&gt;
&lt;p&gt;Now create a user/password file for authentication:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;htpasswd -cm /home/yourusername/subversion/dav_svn.passwd davidwinter
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When prompted, enter your password.&lt;/p&gt;
&lt;h3&gt;Configuring Apache&lt;/h3&gt;
&lt;p&gt;Edit your &lt;code&gt;/usr/local/apache2/conf/httpd.conf&lt;/code&gt; file with the following placed at the end:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/svn&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;DAV&lt;span class="w"&gt; &lt;/span&gt;svn
&lt;span class="w"&gt;  &lt;/span&gt;SVNPath&lt;span class="w"&gt; &lt;/span&gt;/home/yourusername/subversion/repos

&lt;span class="w"&gt;  &lt;/span&gt;AuthType&lt;span class="w"&gt; &lt;/span&gt;Basic
&lt;span class="w"&gt;  &lt;/span&gt;AuthName&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;Subversion&lt;span class="w"&gt; &lt;/span&gt;Repository&amp;quot;
&lt;span class="w"&gt;  &lt;/span&gt;AuthUserFile&lt;span class="w"&gt; &lt;/span&gt;/home/yourusername/subversion/dav_svn.passwd
&lt;span class="w"&gt;  &lt;/span&gt;Require&lt;span class="w"&gt; &lt;/span&gt;valid-user
&lt;span class="nt"&gt;&amp;lt;/Location&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you want access control based on different users, add the following line after the &lt;code&gt;Require valid-user&lt;/code&gt; line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;AuthzSVNAccessFile /home/yourusername/subversion/svn_access_control
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file. Start Apache. To find out what you need to put in the &lt;code&gt;svn_access_control&lt;/code&gt; file, read &lt;a href="/2006/03/03/access-control-for-subversion-with-apache2-and-authz/"&gt;my previous Subversion authentication article here&lt;/a&gt;. for params.&lt;/p&gt;</content><category term="apache"/><category term="dapper"/><category term="howto"/><category term="server"/><category term="source"/><category term="subversion"/><category term="ubuntu"/></entry><entry><title>Ubuntu Dapper Web Server How-to</title><link href="https://davidwinter.dev/2006/08/09/ubuntu-dapper-web-server-how-to/" rel="alternate"/><published>2006-08-09T00:00:00+01:00</published><updated>2006-08-09T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-08-09:/2006/08/09/ubuntu-dapper-web-server-how-to/</id><summary type="html">&lt;p&gt;It&amp;rsquo;s finally here, my updated how-to on how to get Ubuntu Dapper up and running as a home web server. Perfect for hosting those small web sites and blogs. My original &lt;a href="/2006/02/05/ubuntu-5.10-web-server-howto"&gt;Ubuntu 5.10 web server how-to&lt;/a&gt; is still available.&lt;/p&gt;
&lt;p&gt;This updated version is very similar to the 5 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;It&amp;rsquo;s finally here, my updated how-to on how to get Ubuntu Dapper up and running as a home web server. Perfect for hosting those small web sites and blogs. My original &lt;a href="/2006/02/05/ubuntu-5.10-web-server-howto"&gt;Ubuntu 5.10 web server how-to&lt;/a&gt; is still available.&lt;/p&gt;
&lt;p&gt;This updated version is very similar to the 5.10 how-to, however, there are a few changes required. The following changes have been made:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setting up the Multiverse and Universe repositories&lt;/li&gt;
&lt;li&gt;The packages to install Ruby&lt;/li&gt;
&lt;li&gt;Setting a symbolic link for Ruby&lt;/li&gt;
&lt;li&gt;Updating rubygems&lt;/li&gt;
&lt;li&gt;Clearing the rubygems cache&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other than those, the rest of the how-to is the same as the Breezy how-to.&lt;/p&gt;
&lt;p&gt;This how-to assumes that you have a clean install of Ubuntu Dapper (I&amp;rsquo;m not currently using Ubuntu Dapper Server, just the &lt;strong&gt;basic desktop install&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;The first thing to do, is get &lt;code&gt;ssh&lt;/code&gt; installed so that if you like, you can connect and do all of this remotely.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install ssh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are some packages that are needed that aren&amp;rsquo;t in the default repositories for &lt;code&gt;apt&lt;/code&gt;, so you have to enable them manually. Universe and Multiverse are needed.&lt;/p&gt;
&lt;p&gt;To enable them, open up the Synaptic Package Manager&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Settings&lt;/li&gt;
&lt;li&gt;Repositories&lt;/li&gt;
&lt;li&gt;Add&lt;/li&gt;
&lt;li&gt;Ensure that &amp;lsquo;Ubuntu 6.06 LTS&amp;rsquo; is the selected &amp;lsquo;Channel&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Check &amp;lsquo;Community maintained (Universe)&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Check &amp;lsquo;Non-free (Multiverse)&lt;/li&gt;
&lt;li&gt;Click OK and let it rescan the servers.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can then close Synaptic. &lt;code&gt;apt&lt;/code&gt; is now all set up ready for installing the packages we need.&lt;/p&gt;
&lt;p&gt;Before we start installing the packages we want, do a system update:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Ruby&lt;/h3&gt;
&lt;p&gt;All on one line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install irb libdbm-ruby libfcgi-ruby1.8 libgdbm-ruby libmysql-ruby libopenssl-ruby libruby1.8-dbg ri ruby1.8-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In order for Ruby to work ok, do the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ln -s /usr/bin/ruby1.8 /usr/bin/ruby
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will add a symbolic link into your &lt;code&gt;/usr/bin&lt;/code&gt; directory so that the command &lt;code&gt;ruby&lt;/code&gt; works, as opposed to &lt;code&gt;ruby1.8&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;MySQL Server&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install mysql-server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;During this install, a Postfix config screen will appear. Select OK and then &amp;ldquo;No configuration&amp;rdquo;.&lt;/p&gt;
&lt;h3&gt;Ruby Gems &amp;amp; Rails&lt;/h3&gt;
&lt;p&gt;This is the standard way of installing ruby applications.&lt;/p&gt;
&lt;p&gt;Need to download it directly from its web site:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;rubyforge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;frs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;5207&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rubygems&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;11.&lt;/span&gt;&lt;span class="n"&gt;tgz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then extract it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tar xvfz rubygems-0.8.11.tgz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Move into the extracted directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd rubygems-0.8.11
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Run the setu-p program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ruby1.8 setup.rb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Update all installed gems on the system:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo gem update --system
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Take note that there are two dashes preceding &lt;code&gt;system&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now that Ruby Gems is installed, we can install Rails. However, I encountered problems with this and had to clear my rubygems cache first. Do the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gem env gemdir
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will output a path location which you&amp;rsquo;ll need to use for the next command. For me, it was and probably is the same for you, &lt;code&gt;/usr/lib/ruby/gems/1.8&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo rm ABOVE_PATH/source_cache
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will clear your rubygems cache. Now you shouldn&amp;rsquo;t have any problems with installing rails.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo gem install rails -y
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Apache 2&lt;/h3&gt;
&lt;p&gt;Next is the web server I&amp;rsquo;m using. Apache 2. The following command will install Apache 2, FastCGI, FCGI, PHP 5 with MySQL functionality. PHP isn&amp;rsquo;t needed for Ruby or Rails, but I&amp;rsquo;m including it so that I can run PHP apps&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install apache2 libapache2-mod-fcgid libapache2-mod-fastcgi libapache2-mod-php5 php5-mysql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once that&amp;rsquo;s done, we&amp;rsquo;ll need to enable the Apache mods we&amp;rsquo;ll be using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo a2enmod fcgid
sudo a2enmod fastcgi
sudo a2enmod rewrite
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll notice I&amp;rsquo;ve installed two different types of Fast CGI. That&amp;rsquo;s because at some point I want to try them both out. However, at the moment, I&amp;rsquo;ve only had success with getting FastCGI working decently.&lt;/p&gt;
&lt;p&gt;Restart Apache to make sure all is well.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;FastCGI&lt;/h3&gt;
&lt;p&gt;I thought FastCGI would have been installed after doing the libapache2-mod-fastcgi - but for some reason, you have to install it manually.&lt;/p&gt;
&lt;p&gt;In order to configure and build from the source files, you need to download some basic files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install build-essential
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, grab the FastCGI files from the web site:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;wget http://fastcgi.com/dist/fcgi-2.4.0.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Extract:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tar xvfz fcgi-2.4.0.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Move into the directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd fcgi-2.4.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Configure the installer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./configure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, that is all of the Apache and FastCGI files installed. Later, we&amp;rsquo;ll need to configure it all.&lt;/p&gt;
&lt;h3&gt;Webmin&lt;/h3&gt;
&lt;p&gt;Webmin is ugly, but it works, and it lets us configure Apache and the Nameserver easily.&lt;/p&gt;
&lt;p&gt;Go to http://www.webmin.com/ and download the latest version of webmin in tar.gz format.&lt;/p&gt;
&lt;p&gt;Once downloaded, extract it (filename may vary depending on the version you download):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tar xvfz webmin-1.260.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Move into the directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd webmin-1.260
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Run the set-up program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ./setup.sh /usr/local/webmin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can use the default settings for this, or change them if you know what you&amp;rsquo;re doing. Be sure to set a password you can remember.&lt;/p&gt;
&lt;p&gt;At the end of the set-up you&amp;rsquo;ll be given an address to use to connect to webmin. Remember this! and go to it straight away and login.&lt;/p&gt;
&lt;p&gt;Do the following to configure Webmin to work with Apache:
1. At the top, click on the &amp;ldquo;Servers&amp;rdquo; link.
2. Select Apache Webserver.
3. Select Module Config.
4. Set the following values:
    * Apache Server Root - /etc/apache2
    * Path to httpd executable - /usr/sbin/apache2
    * Path to httpd.conf - /etc/apache2/httpd.conf
    * Command to start Apache - /etc/init.d/apache2 start
    * Command to stop Apache - /etc/init.d/apache2 stop&lt;/p&gt;
&lt;p&gt;Save these settings.&lt;/p&gt;
&lt;h3&gt;Nameserver&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m no DNS expert, so this is very vague and I suggest you go read a howto on DNS&amp;hellip; &lt;a href="http://rimuhosting.com/support/bindviawebmin.jsp"&gt;here&amp;rsquo;s one&lt;/a&gt; I used to complete this part.&lt;/p&gt;
&lt;p&gt;This will be different depending on your set-ups. For me, I have my domain name pointing to my web server in America that hosts http://commanderbond.net&lt;/p&gt;
&lt;p&gt;On the server, there, I have the DNS pointing to my Internet IP at home, here in the UK.&lt;/p&gt;
&lt;p&gt;The nameserver I&amp;rsquo;m using is Bind.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install bind9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once that&amp;rsquo;s installed, we need to configure it in Webmin.
1. Click the &amp;ldquo;Servers&amp;rdquo; link.
2. Select BIND DNS Server.
3. A message will appear about a configuration file. Select the 3rd option &amp;ldquo;Setup as an internet name server, but use Webmin&amp;rsquo;s older root server information&amp;rdquo;
4. Create a Master Zone and enter the following details:
    * Domain Name - yourdomain.com
    * Email - you@anemail.com
5. Click on &amp;ldquo;Create&amp;rdquo;.
6. Click on the &amp;ldquo;Address&amp;rdquo; link.
7. Create a new Address record using the following:
    * Name - yourdomain.com. (including the trailing dot)
    * Address - your Internet IP address
8. Click on &amp;ldquo;Create&amp;rdquo;.
9. Go to the Module Index.
10. Click on &amp;ldquo;Apply Changes&amp;rdquo;.&lt;/p&gt;
&lt;h3&gt;Set-up your web site&lt;/h3&gt;
&lt;p&gt;You&amp;rsquo;ll need somewhere to store your web site files, so I suggest to first of all create a &lt;code&gt;public_html&lt;/code&gt; directory in your user directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir ~/public_html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we&amp;rsquo;ll create a test HTML file to check all is working so far.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nano ~/public_html/index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside it put the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hopefully&lt;span class="w"&gt; &lt;/span&gt;you&lt;span class="w"&gt; &lt;/span&gt;can&lt;span class="w"&gt; &lt;/span&gt;see&lt;span class="w"&gt; &lt;/span&gt;this...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file using Control O and then Control X to quit Nano.&lt;/p&gt;
&lt;p&gt;Now, set the permissions of the file so it&amp;rsquo;s visible to the world:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;chmod 644 ~/public_html/index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In Webmin, go to the Apache configuration.&lt;/p&gt;
&lt;p&gt;Create a new Virtual Server with the following:
* Document Root - home/yourusername/public_html
* Server Name - yourdomain.com&lt;/p&gt;
&lt;p&gt;Save the settings. Now restart Apache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now visit http://yourdomain.com/~yourusername/ and you should see:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hopefully you can see this&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If so, excellent! If not, hmmm&amp;hellip; maybe you didn&amp;rsquo;t follow everything? or I made a mistake somewhere&amp;hellip; leave a comment below.&lt;/p&gt;
&lt;p&gt;Take a 5 minute break!&lt;/p&gt;
&lt;p&gt;Refreshed? Right. Moving on&amp;hellip;&lt;/p&gt;
&lt;h3&gt;phpMyAdmin for MySQL management&lt;/h3&gt;
&lt;p&gt;Go to http://www.phpmyadmin.net/home_page/index.php and download the latest stable release of phpMyAdmin in tar.gz format.&lt;/p&gt;
&lt;p&gt;Extract:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tar xvfz phpMyAdmin-2.7.0-pl2.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Move the directory to some place helpful:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mv phpMyAdmin-2.7.0-pl2 ~/phpmyadmin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Move into that directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ~/phpmyadmin/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create a new configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cp config.default.php config.inc.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Change the authentication mode to http&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gedit config.inc.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Change this line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;Servers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;auth_type&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&amp;hellip;to this line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;Servers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;auth_type&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file.&lt;/p&gt;
&lt;p&gt;Back in the command line, we need to set the root password, because by default, there isn&amp;rsquo;t one!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mysql -u root
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll then enter the MySQL console. Enter the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;UPDATE mysql.user SET Password=PASSWORD(&amp;#39;newpasswordhere&amp;#39;) WHERE User=&amp;#39;root&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will set the root password. Now flush the privileges:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;FLUSH PRIVILEGES;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now exit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, we want phpMyAdmin accessible on the server &amp;lsquo;globally&amp;rsquo;. So that it doesn&amp;rsquo;t matter what address we&amp;rsquo;re using, we&amp;rsquo;ll still be able to access it.&lt;/p&gt;
&lt;p&gt;In Webmin, under Apache Webserver:
1. Select &amp;ldquo;Default Server&amp;rdquo;
2. Aliases and Redirects
3. Under &amp;ldquo;Document directory aliases&amp;rdquo; enter &lt;code&gt;/phpmyadmin/&lt;/code&gt; into the first text box, and &lt;code&gt;/home/davidwinter/phpmyadmin/&lt;/code&gt; into the box to the right of that one.&lt;/p&gt;
&lt;p&gt;Save, and in the Terminal restart apache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Go to http://yourdomain.com/phpmyadmin/&lt;/p&gt;
&lt;p&gt;Login in using &amp;ldquo;root&amp;rdquo; and the password you set in the MySQL console.&lt;/p&gt;
&lt;p&gt;You can do any MySQL configuration here. For me, I restored my Typo database for this blog from a backup.&lt;/p&gt;
&lt;h3&gt;FastCGI configuration with a Rails application&lt;/h3&gt;
&lt;p&gt;This part is what gets a Rails app running really fast.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll need to configure the FastCGI config file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/apache2/mods-enabled/fastcgi.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here is my config file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;IfModule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mod_fastcgi.c&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;#FastCgiWrapper&lt;span class="w"&gt; &lt;/span&gt;/usr/lib/apache2/suexec2
&lt;span class="w"&gt;  &lt;/span&gt;FastCgiIpcDir&lt;span class="w"&gt; &lt;/span&gt;/var/lib/apache2/fastcgi
&lt;span class="w"&gt;  &lt;/span&gt;FastCgiConfig&lt;span class="w"&gt; &lt;/span&gt;-maxClassProcesses&lt;span class="w"&gt; &lt;/span&gt;2&lt;span class="w"&gt; &lt;/span&gt;-maxProcesses&lt;span class="w"&gt; &lt;/span&gt;2&lt;span class="w"&gt; &lt;/span&gt;-minProcesses&lt;span class="w"&gt; &lt;/span&gt;2&lt;span class="w"&gt; &lt;/span&gt;-processSlack&lt;span class="w"&gt; &lt;/span&gt;2
&lt;span class="w"&gt;  &lt;/span&gt;FastCgiServer&lt;span class="w"&gt; &lt;/span&gt;/home/davidwinter/typo/public/dispatch.fcgi&lt;span class="w"&gt; &lt;/span&gt;-idle-timeout&lt;span class="w"&gt; &lt;/span&gt;120&lt;span class="w"&gt; &lt;/span&gt;-processes&lt;span class="w"&gt; &lt;/span&gt;2&lt;span class="w"&gt; &lt;/span&gt;-initial-env&lt;span class="w"&gt; &lt;/span&gt;RAILS_ENV=production
&lt;span class="nt"&gt;&amp;lt;/IfModule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The following line of the above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;FastCgiServer /home/davidwinter/typo/public/dispatch.fcgi -idle-timeout 120 -processes 2 -initial-env RAILS_ENV=production
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Is important. You need to specifiy a line like this for each Rails app you&amp;rsquo;ll be using under FastCGI.&lt;/p&gt;
&lt;p&gt;Now, in your Rails application directory check that in &lt;code&gt;public/.htaccess&lt;/code&gt; has this line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;AddHandler fastcgi-script .fcgi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And, that in the rewrite rules section, it has this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&amp;hellip;instead of:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice &lt;code&gt;.fcgi&lt;/code&gt; instead of &lt;code&gt;.cgi&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s about it!&lt;/p&gt;
&lt;p&gt;Give Apache one final restart:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And you should now have everything working.&lt;/p&gt;
&lt;p&gt;As I said, any problems, leave a comment and I&amp;rsquo;ll try and help.&lt;/p&gt;</content><category term="apache"/><category term="dapper"/><category term="howto"/><category term="rails"/><category term="ruby"/><category term="ubuntu"/></entry><entry><title>Set-up Typo 4 on Ubuntu Dapper</title><link href="https://davidwinter.dev/2006/07/26/set-up-typo-4-on-ubuntu-dapper/" rel="alternate"/><published>2006-07-26T00:00:00+01:00</published><updated>2006-07-26T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-07-26:/2006/07/26/set-up-typo-4-on-ubuntu-dapper/</id><summary type="html">&lt;p&gt;It was very annoying to find out that the brand spanking new installer for Typo wasn&amp;rsquo;t going to install over rubygems.  The irritating part was that it was SQLite causing the problem because it&amp;rsquo;s a dependency of the Typo gem. No idea why. But I don&amp;rsquo;t want …&lt;/p&gt;</summary><content type="html">&lt;p&gt;It was very annoying to find out that the brand spanking new installer for Typo wasn&amp;rsquo;t going to install over rubygems.  The irritating part was that it was SQLite causing the problem because it&amp;rsquo;s a dependency of the Typo gem. No idea why. But I don&amp;rsquo;t want to SQLite - I&amp;rsquo;m running MySQL on Apache.&lt;/p&gt;
&lt;p&gt;So anyway, here&amp;rsquo;s how I got it working. Thanks to &lt;code&gt;sprewell&lt;/code&gt; on the Typo IRC channel.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Download Typo from Subversion.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;svn co svn://typosphere.org/svn/typo/trunk typo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make sure that you&amp;rsquo;re inside that directory that was downloaded from Subversion.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;bin/typo config ~/typo web-server=external database=mysql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Grab the MySQL schema from &lt;code&gt;db/mysql.schema.sql&lt;/code&gt; and manually run it on your MySQL database of choice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go into &lt;code&gt;config/&lt;/code&gt; and make sure you get the &lt;code&gt;database.yml&lt;/code&gt; file set-up to use your database settings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Access your Typo install in your browser and you should get a prompt asking you for your admin details.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Blog away!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</content><category term="howto"/><category term="rails"/><category term="typo"/><category term="ubuntu"/></entry><entry><title>Cocoa-Java and Jar Frameworks</title><link href="https://davidwinter.dev/2006/07/20/cocoa-java-and-jar-frameworks/" rel="alternate"/><published>2006-07-20T00:00:00+01:00</published><updated>2006-07-20T00:00:00+01:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-07-20:/2006/07/20/cocoa-java-and-jar-frameworks/</id><summary type="html">&lt;p&gt;Note: Didn&amp;rsquo;t have time to really write this article up - maybe some time I will - but I&amp;rsquo;m posting it here just in case it comes in handy for someone.&lt;/p&gt;
&lt;p&gt;Now that I&amp;rsquo;m finished with coursework, and just awaiting my exams to start on Wednesday (can&amp;rsquo;t wait …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Note: Didn&amp;rsquo;t have time to really write this article up - maybe some time I will - but I&amp;rsquo;m posting it here just in case it comes in handy for someone.&lt;/p&gt;
&lt;p&gt;Now that I&amp;rsquo;m finished with coursework, and just awaiting my exams to start on Wednesday (can&amp;rsquo;t wait!) - I&amp;rsquo;ve got a chance to work on a little application I&amp;rsquo;ve been meaning to write for the last year or so. I&amp;rsquo;ve just never had the opportunity to get on with it.&lt;/p&gt;
&lt;p&gt;Most of this year, I&amp;rsquo;ve been learning to develop Java applications using Swing. However, the application I&amp;rsquo;m developing is for the Mac only. I want to be using the Cocoa-Java bridge for the time being as I can&amp;rsquo;t find an RSS parsing framework as nice as Rome, which is written in Java.&lt;/p&gt;
&lt;p&gt;So, I want to include the .jar file that holds the Rome framework in my Xcode application. This assumes you have a Cocoa-Java application set-up in Xcode.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Project &amp;gt; Add To Project&lt;/li&gt;
&lt;li&gt;Select the file&lt;/li&gt;
&lt;li&gt;New Build Phase&lt;/li&gt;
&lt;li&gt;Select Executable&lt;/li&gt;
&lt;li&gt;Drag jar to new build phase.&lt;/li&gt;
&lt;li&gt;Project &amp;gt; Edit Active Target&lt;/li&gt;
&lt;li&gt;Cocoa Java Specific&lt;/li&gt;
&lt;li&gt;Change Root Directory to &amp;lsquo;Contents&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Change app.jar to Resources/Java/app.jar&lt;/li&gt;
&lt;li&gt;Add desired Jar file by adding MacOS/rome.jar&lt;/li&gt;
&lt;/ol&gt;</content><category term="howto"/><category term="java"/><category term="mac"/><category term="xcode"/></entry><entry><title>Using Tomcat Ant tasks</title><link href="https://davidwinter.dev/2006/03/21/using-tomcat-ant-tasks/" rel="alternate"/><published>2006-03-21T00:00:00+00:00</published><updated>2006-03-21T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-03-21:/2006/03/21/using-tomcat-ant-tasks/</id><summary type="html">&lt;p&gt;I&amp;rsquo;m now really loving Ant for compiling my Java projects together. It really has solved the problem of figuring out what to update, or going through countless commands to compile each package etc.&lt;/p&gt;
&lt;p&gt;You could be wondering why I don&amp;rsquo;t just use a fancy IDE, like Eclipse to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;m now really loving Ant for compiling my Java projects together. It really has solved the problem of figuring out what to update, or going through countless commands to compile each package etc.&lt;/p&gt;
&lt;p&gt;You could be wondering why I don&amp;rsquo;t just use a fancy IDE, like Eclipse to do all this for me? Well&amp;hellip; I&amp;rsquo;ve tried. But&amp;hellip; I just can&amp;rsquo;t &amp;lsquo;like&amp;rsquo; Eclipse. I admit, I was very impressed with it - tons of functionallity, but in the end, I just couldn&amp;rsquo;t give up using the beautiful TextMate. Eclipse felt cluttered and I was claustrophobic using it.&lt;/p&gt;
&lt;p&gt;Pathetic excuse I know, but I need something I can get on and work with.&lt;/p&gt;
&lt;p&gt;Anyway - enough side-tracking on talk of Eclipse.&lt;/p&gt;
&lt;p&gt;Ant. Java compiling made easy. Bring on Tomcat extension tasks with it and that saves me another aspirin for working on my Tomcat coursework which is to develop a web based quiz. To install the Tomcat tasks for Ant on Mac OS X, you just need to copy them over:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cp /usr/local/apache-tomcat-5.5.16/server/lib/catalina-ant.jar /Developer/Java/Ant/lib
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that this installs the Tomcat tasks to the default Developer Tools install of Ant.  If you&amp;rsquo;ve installed Ant manually, you&amp;rsquo;ll need to change the paths above accordingly.&lt;/p&gt;
&lt;p&gt;Once the &lt;code&gt;.jar&lt;/code&gt; is copied over, in your &lt;code&gt;build.xml&lt;/code&gt; files for your various projects, you&amp;rsquo;ll need to include the following tags:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;lt;taskdef name=&amp;quot;deploy&amp;quot; classname=&amp;quot;org.apache.catalina.ant.DeployTask&amp;quot; /&amp;gt;
&amp;lt;taskdef name=&amp;quot;undeploy&amp;quot; classname=&amp;quot;org.apache.catalina.ant.UndeployTask&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These task definitions only cover &lt;code&gt;deploy&lt;/code&gt; and &lt;code&gt;undeploy&lt;/code&gt; tasks. To use them in your project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;target&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;undeploy&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;undeploy&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;tomcat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="na"&gt;username=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;tomcat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="na"&gt;password=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;tomcat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/yourwebapp&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/target&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Where &lt;code&gt;tomcat.manager&lt;/code&gt; is your URL to your Tomcat manager. Usually &lt;code&gt;http://localhost:8080/manager&lt;/code&gt;. &lt;code&gt;tomcat.username&lt;/code&gt; and &lt;code&gt;tomcat.password&lt;/code&gt; are self-explanatory. Then just substitute &lt;code&gt;yourwebapp&lt;/code&gt; with the name of your tomcat application directory located inside the &lt;code&gt;webapp&lt;/code&gt; directory. For my current coursework, this is &lt;code&gt;webquiz&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;deploy&lt;/code&gt; task is very similar:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;target&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;deploy&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;depends=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;war&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;deploy&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;tomcat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="na"&gt;username=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;tomcat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="na"&gt;password=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;tomcat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;ant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="na"&gt;update=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;
        &lt;span class="na"&gt;localWar=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;war&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;ant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.war&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/target&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I have another target that creates a WAR file of my entire web application. This is what I&amp;rsquo;ll use to deploy my application. The only additional attributes in the &lt;code&gt;deploy&lt;/code&gt; task are &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;localWar&lt;/code&gt;. &lt;code&gt;update&lt;/code&gt; will replace an existing application if it already exists so that you have the latest working copy. &lt;code&gt;localWar&lt;/code&gt; is the location of the WAR file you want to deploy.&lt;/p&gt;
&lt;p&gt;Simple. Hope I&amp;rsquo;ve explained this clear enough.&lt;/p&gt;
&lt;p&gt;As of writing this, I&amp;rsquo;m having some trouble getting this working with my iBook, which I assumed had the same set-up as my Intel iMac - of which, the above tasks are working perfectly.&lt;/p&gt;</content><category term="howto"/><category term="java"/><category term="tomcat"/></entry><entry><title>Access Control for Subversion with Apache2 and Authz</title><link href="https://davidwinter.dev/2006/03/03/access-control-for-subversion-with-apache2-and-authz/" rel="alternate"/><published>2006-03-03T00:00:00+00:00</published><updated>2006-03-03T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-03-03:/2006/03/03/access-control-for-subversion-with-apache2-and-authz/</id><summary type="html">&lt;p&gt;My group project at University now consists of three smaller projects that provide an overall RSS service. I want to let the guys work on these, while still letting me keep my other coursework jut accessible to me. At the moment, I just have basic http authentication set-up which isn …&lt;/p&gt;</summary><content type="html">&lt;p&gt;My group project at University now consists of three smaller projects that provide an overall RSS service. I want to let the guys work on these, while still letting me keep my other coursework jut accessible to me. At the moment, I just have basic http authentication set-up which isn&amp;rsquo;t so great for pulling off what I want.&lt;/p&gt;
&lt;p&gt;Please welcome on stage the Apache2 mod, &lt;code&gt;authz_svn&lt;/code&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;If you followed my other &lt;a href="/2006/02/16/subversion-over-apache-2-on-ubuntu"&gt;howto&lt;/a&gt;, you&amp;rsquo;ll have all the pre-requisites for this.&lt;/p&gt;
&lt;p&gt;First of all, we need to create an Access Control file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/apache2/svn_access_control
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this file, you&amp;rsquo;ll want to put some rules. I&amp;rsquo;ll first of all go over these and then provide some examples.&lt;/p&gt;
&lt;h3&gt;Permissions&lt;/h3&gt;
&lt;p&gt;There are only two types of permission:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read only - &lt;code&gt;r&lt;/code&gt; - a user can check-out a copy of a project.&lt;/li&gt;
&lt;li&gt;Read and Write - &lt;code&gt;rw&lt;/code&gt; - a user can check-out and commit changes to a project.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Users&lt;/h3&gt;
&lt;p&gt;These are the same usernames that you have set in your password file that you created in the previous &lt;a href="/2006/02/16/subversion-over-apache-2-on-ubuntu"&gt;howto&lt;/a&gt;. You can always add more users to this file using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo htpasswd2 -m /etc/apache2/dav_svn.passwd bill
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When prompted, enter the password for the user.&lt;/p&gt;
&lt;h3&gt;Repository Location&lt;/h3&gt;
&lt;p&gt;You specify the above rules in certain locations for the repository. These go between square brackets.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;[/]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above will specify rules for the root of the repository.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;[/wowapp/trunk]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above will specify rules for a project named &amp;lsquo;wowapp&amp;rsquo; in the trunk location.&lt;/p&gt;
&lt;h3&gt;User Groups&lt;/h3&gt;
&lt;p&gt;You can create groups of users and then use those for rules. You do this under a special heading in square brackets:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[groups]&lt;/span&gt;
&lt;span class="na"&gt;mygroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;dave, mike&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create a group called &amp;lsquo;mygroup&amp;rsquo; which &amp;lsquo;dave&amp;rsquo; and &amp;lsquo;mike&amp;rsquo; belongs to.&lt;/p&gt;
&lt;p&gt;And now for some examples.&lt;/p&gt;
&lt;h3&gt;Examples&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[groups]&lt;/span&gt;
&lt;span class="na"&gt;team&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;bob, bill&lt;/span&gt;
&lt;span class="na"&gt;devteam&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;bob, barry, brett&lt;/span&gt;

&lt;span class="k"&gt;[/]&lt;/span&gt;
&lt;span class="na"&gt;@team&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;
&lt;span class="na"&gt;bob&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;rw&lt;/span&gt;

&lt;span class="k"&gt;[/wowapp/trunk]&lt;/span&gt;
&lt;span class="na"&gt;@team&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;
&lt;span class="na"&gt;@devteam&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;rw&lt;/span&gt;
&lt;span class="na"&gt;brenda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;rw&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Created a group &lt;code&gt;team&lt;/code&gt; which has two members; &lt;code&gt;bob&lt;/code&gt; and &lt;code&gt;bill&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Created another group, called &lt;code&gt;devteam&lt;/code&gt; which has three members; &lt;code&gt;bob&lt;/code&gt;, &lt;code&gt;barry&lt;/code&gt;, &lt;code&gt;brett&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In the root of the repository, I&amp;rsquo;ve given the group &lt;code&gt;team&lt;/code&gt; read permissions.&lt;/li&gt;
&lt;li&gt;Also, in the root, &lt;code&gt;bob&lt;/code&gt; has read and write permissions.&lt;/li&gt;
&lt;li&gt;In the trunk of &lt;code&gt;wowapp&lt;/code&gt;, the group &lt;code&gt;team&lt;/code&gt; has read permission.&lt;/li&gt;
&lt;li&gt;Also, the &lt;code&gt;devteam&lt;/code&gt; group has read and write permissions.&lt;/li&gt;
&lt;li&gt;And another user, called &lt;code&gt;brenda&lt;/code&gt; has read and write permissions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you&amp;rsquo;ve created your desired access controll file, save the changes in nano by hitting &lt;code&gt;CTRL O&lt;/code&gt;, hit enter to save the name, then &lt;code&gt;CTRL X&lt;/code&gt; to quit Nano.&lt;/p&gt;
&lt;p&gt;We just need to now link this access control file with our Subversion set-up.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/apache2/mods-enabled/dav_svn.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s the example from the previous how-to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/svn&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;DAV&lt;span class="w"&gt; &lt;/span&gt;svn
&lt;span class="w"&gt;  &lt;/span&gt;SVNPath&lt;span class="w"&gt; &lt;/span&gt;/home/svn

&lt;span class="w"&gt;  &lt;/span&gt;AuthType&lt;span class="w"&gt; &lt;/span&gt;Basic
&lt;span class="w"&gt;  &lt;/span&gt;AuthName&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;Subversion&lt;span class="w"&gt; &lt;/span&gt;Repository&amp;quot;
&lt;span class="w"&gt;  &lt;/span&gt;AuthUserFile&lt;span class="w"&gt; &lt;/span&gt;/etc/apache2/dav_svn.passwd
&lt;span class="w"&gt;  &lt;/span&gt;Require&lt;span class="w"&gt; &lt;/span&gt;valid-user
&lt;span class="nt"&gt;&amp;lt;/Location&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All you need to add is the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;AuthzSVNAccessFile /etc/apache2/svn_access_control
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So that the file looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/svn&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;DAV&lt;span class="w"&gt; &lt;/span&gt;svn
&lt;span class="w"&gt;  &lt;/span&gt;SVNPath&lt;span class="w"&gt; &lt;/span&gt;/home/svn

&lt;span class="w"&gt;  &lt;/span&gt;AuthType&lt;span class="w"&gt; &lt;/span&gt;Basic
&lt;span class="w"&gt;  &lt;/span&gt;AuthName&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;Subversion&lt;span class="w"&gt; &lt;/span&gt;Repository&amp;quot;
&lt;span class="w"&gt;  &lt;/span&gt;AuthUserFile&lt;span class="w"&gt; &lt;/span&gt;/etc/apache2/dav_svn.passwd

&lt;span class="w"&gt;  &lt;/span&gt;AuthzSVNAccessFile&lt;span class="w"&gt; &lt;/span&gt;/etc/apache2/svn_access_control

&lt;span class="w"&gt;  &lt;/span&gt;Require&lt;span class="w"&gt; &lt;/span&gt;valid-user
&lt;span class="nt"&gt;&amp;lt;/Location&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file, and then restart Apache2:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should now have access control working for Subversion over Apache2.&lt;/p&gt;</content><category term="apache"/><category term="howto"/><category term="subversion"/><category term="ubuntu"/><category term="uni"/></entry><entry><title>Tomcat on Mac OS X Tiger</title><link href="https://davidwinter.dev/2006/02/20/tomcat-on-mac-os-x-tiger/" rel="alternate"/><published>2006-02-20T00:00:00+00:00</published><updated>2006-02-20T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-02-20:/2006/02/20/tomcat-on-mac-os-x-tiger/</id><summary type="html">&lt;p&gt;Download the &amp;lsquo;Core&amp;rsquo; .tar.gz version of Tomcat (as of this writing 5.5.15) from http://tomcat.apache.org/download-55.cgi. Extract and move the folder:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo mv ~/Desktop/apache-tomcat-5.5.15 /usr/local/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s all you need to do to actually install Tomcat&amp;ndash;nice and simple. Now …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Download the &amp;lsquo;Core&amp;rsquo; .tar.gz version of Tomcat (as of this writing 5.5.15) from http://tomcat.apache.org/download-55.cgi. Extract and move the folder:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo mv ~/Desktop/apache-tomcat-5.5.15 /usr/local/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s all you need to do to actually install Tomcat&amp;ndash;nice and simple. Now to create some start and stop scripts&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd /usr/local/bin
sudo nano start_tomcat
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Enter the following and save:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CATALINA_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/apache-tomcat-5.5.15
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;JAVA_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/System/Library/Frameworks/JavaVM.framework/Home
&lt;span class="nv"&gt;$CATALINA_HOME&lt;/span&gt;/bin/startup.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now a stop script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano stop_tomcat
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Enter the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CATALINA_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/apache-tomcat-5.5.15
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;JAVA_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/System/Library/Frameworks/JavaVM.framework/Home
&lt;span class="nv"&gt;$CATALINA_HOME&lt;/span&gt;/bin/shutdown.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Voila! Now to start Tomcat, use &lt;code&gt;/usr/local/bin/start_tomcat&lt;/code&gt; and to stop it use &lt;code&gt;/usr/local/bin/stop_tomcat&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you have &lt;code&gt;/usr/local/bin&lt;/code&gt; included in your PATH environment variable, then you can start and stop Tomcat using &lt;code&gt;start_tomcat&lt;/code&gt; and &lt;code&gt;stop_tomcat&lt;/code&gt; respectively straight from the Terminal.&lt;/p&gt;
&lt;p&gt;When Tomcat is started, you can see the installation by going to &lt;a href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt;. In order to manage Tomcat, you&amp;rsquo;ll need to modify the &lt;code&gt;tomcat-users.xml&lt;/code&gt; file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cd /usr/local/apache-tomcat-5.5.15/conf&lt;/span&gt;
&lt;span class="n"&gt;sudo nano tomcat-users.xml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside this file, modify it so it includes the following tags:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;#39;1.0&amp;#39; encoding=&amp;#39;utf-8&amp;#39;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;tomcat-users&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;role&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;rolename=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;manager&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;role&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;rolename=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;username=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;davidwinter&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;password=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;123&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;roles=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;admin,manager&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/tomcat-users&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Where &lt;code&gt;davidwinter&lt;/code&gt; is the username you want to use, and &lt;code&gt;123&lt;/code&gt; being the password you desire.&lt;/p&gt;
&lt;p&gt;You can then manage your Tomcat applications using this URL: &lt;code&gt;http://localhost:8080/manager/html&lt;/code&gt;&lt;/p&gt;</content><category term="howto"/><category term="java"/><category term="mac"/><category term="tomcat"/></entry><entry><title>Mac friendly Java apps in a few lines</title><link href="https://davidwinter.dev/2006/02/18/mac-friendly-java-apps-in-a-few-lines/" rel="alternate"/><published>2006-02-18T00:00:00+00:00</published><updated>2006-02-18T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-02-18:/2006/02/18/mac-friendly-java-apps-in-a-few-lines/</id><summary type="html">&lt;p&gt;Mac menu-bar? Set this before you initiate your &lt;code&gt;JFrame&lt;/code&gt; in your &lt;code&gt;main&lt;/code&gt; class:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;System.setProperty(&amp;quot;apple.laf.useScreenMenuBar&amp;quot;, &amp;quot;true&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Other systems will just ignore this and the menu-bar will appear as normal for that system.&lt;/p&gt;
&lt;p&gt;Command keyboard button as default for keyboard shortcuts?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;yourJMenuItemObject.setAccelerator(
    KeyStroke.getKeyStroke( java.awt.event …&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Mac menu-bar? Set this before you initiate your &lt;code&gt;JFrame&lt;/code&gt; in your &lt;code&gt;main&lt;/code&gt; class:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;System.setProperty(&amp;quot;apple.laf.useScreenMenuBar&amp;quot;, &amp;quot;true&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Other systems will just ignore this and the menu-bar will appear as normal for that system.&lt;/p&gt;
&lt;p&gt;Command keyboard button as default for keyboard shortcuts?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;yourJMenuItemObject.setAccelerator(
    KeyStroke.getKeyStroke( java.awt.event.KeyEvent.VK_O,
        Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will get the default key for the operating system the Java app is running on. So that means &amp;lsquo;Control&amp;rsquo; for Windows and &amp;lsquo;Command&amp;rsquo; for Mac.&lt;/p&gt;
&lt;p&gt;With those small things, you can make a Java app feel like a true part of the Mac family without sacrificing it working on other systems or the need for a separate binary.&lt;/p&gt;</content><category term="howto"/><category term="java"/></entry><entry><title>Subversion over Apache 2 on Ubuntu</title><link href="https://davidwinter.dev/2006/02/16/subversion-over-apache-2-on-ubuntu/" rel="alternate"/><published>2006-02-16T00:00:00+00:00</published><updated>2006-02-16T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-02-16:/2006/02/16/subversion-over-apache-2-on-ubuntu/</id><summary type="html">&lt;p&gt;If your one of my regular readers (ha!), then you&amp;rsquo;ll know I&amp;rsquo;m starting a Group Project for University. We have 7 members in the group and without some sort of version control - managing the code we&amp;rsquo;re about to produce would be hell! So I&amp;rsquo;m setting up …&lt;/p&gt;</summary><content type="html">&lt;p&gt;If your one of my regular readers (ha!), then you&amp;rsquo;ll know I&amp;rsquo;m starting a Group Project for University. We have 7 members in the group and without some sort of version control - managing the code we&amp;rsquo;re about to produce would be hell! So I&amp;rsquo;m setting up Subversion on my home server as a repository. Following are the steps I used to set-up Subversion over Apache 2 on my Ubuntu server.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m assuming you have Apache 2 already set-up. The only extra packages to download and install are &lt;code&gt;subversion&lt;/code&gt; and &lt;code&gt;libapache2-svn&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install subversion libapache2-svn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will download and install Subversion and the SVN module for Apache 2. The module itself uses WebDAV to transmit files between Subversion - so this means everything can go across port 80 without the hassle of having to worry about a firewall.&lt;/p&gt;
&lt;p&gt;The install should automatically enable the module, but just to check:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo a2enmod dav_svn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It should come up saying it&amp;rsquo;s already enabled. If not, it will enable it for you.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll need to configure Apache now:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/apache2/mods-enabled/dav_svn.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Edit the file to look something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/svn&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;DAV&lt;span class="w"&gt; &lt;/span&gt;svn
&lt;span class="w"&gt;  &lt;/span&gt;SVNPath&lt;span class="w"&gt; &lt;/span&gt;/home/svn

&lt;span class="w"&gt;  &lt;/span&gt;AuthType&lt;span class="w"&gt; &lt;/span&gt;Basic
&lt;span class="w"&gt;  &lt;/span&gt;AuthName&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;Subversion&lt;span class="w"&gt; &lt;/span&gt;Repository&amp;quot;
&lt;span class="w"&gt;  &lt;/span&gt;AuthUserFile&lt;span class="w"&gt; &lt;/span&gt;/etc/apache2/dav_svn.passwd
&lt;span class="w"&gt;  &lt;/span&gt;Require&lt;span class="w"&gt; &lt;/span&gt;valid-user
&lt;span class="nt"&gt;&amp;lt;/Location&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Change &lt;code&gt;/home/svn&lt;/code&gt; to whatever the location of your repository is. If you haven&amp;rsquo;t created one yet, then do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo mkdir /home/svn
sudo svnadmin create /home/svn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, you need to make Apache the owner of the repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo chown -R www-data /home/svn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To secure Subversion, do the following to create a password file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo htpasswd2 -cm /etc/apache2/dav_svn.passwd bob
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Replace &lt;code&gt;bob&lt;/code&gt; with whatever username you want to use, and then when prompted enter a password.&lt;/p&gt;
&lt;p&gt;Now restart Apache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That should now all be set-up. You can try it by visiting your server &lt;code&gt;http://you.server/svn&lt;/code&gt;. You should get a username/password dialog which you enter the details you created.&lt;/p&gt;</content><category term="apache"/><category term="howto"/><category term="subversion"/><category term="ubuntu"/></entry><entry><title>Using IRC and other IM apps at University</title><link href="https://davidwinter.dev/2006/02/06/using-irc-and-other-im-apps-at-university/" rel="alternate"/><published>2006-02-06T00:00:00+00:00</published><updated>2006-02-06T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-02-06:/2006/02/06/using-irc-and-other-im-apps-at-university/</id><summary type="html">&lt;p&gt;At University, they&amp;rsquo;ve blocked ports for all IM applications, including IRC. This sucks, because IRC can actually be really helpful for asking for advice on things such as C++ or C. Also, our computing society has an IRC channel (#wmin-compsoc on Quakenet) and it was a real pain that …&lt;/p&gt;</summary><content type="html">&lt;p&gt;At University, they&amp;rsquo;ve blocked ports for all IM applications, including IRC. This sucks, because IRC can actually be really helpful for asking for advice on things such as C++ or C. Also, our computing society has an IRC channel (#wmin-compsoc on Quakenet) and it was a real pain that we couldn&amp;rsquo;t communicate with members at the University.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d seen Douglas Bowman&amp;rsquo;s &amp;ldquo;how-to&amp;rdquo; on &lt;a href="http://www.stopdesign.com/log/2005/02/07/secure-email.html"&gt;secure email&lt;/a&gt; using SSH tunnelling and thought that perhaps I could use this to get around the problem I was having. And, I&amp;rsquo;d be right in thinking that.&lt;/p&gt;
&lt;h4&gt;SSH rocks&lt;/h4&gt;
&lt;p&gt;I can&amp;rsquo;t stress how cool SSH is - it let&amp;rsquo;s me control my iMac at home while I&amp;rsquo;m at Uni, I can transfer my files backwards and forwards and &lt;em&gt;now&lt;/em&gt; lets me connect to IRC.&lt;/p&gt;
&lt;p&gt;On my iBook that I use at Uni, I&amp;rsquo;ve got &lt;a href="http://colloquy.info"&gt;Colloquy&lt;/a&gt; as my preferred IRC client. In the Terminal on my iBook I enter in:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6668&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="n"&gt;irc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quakenet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;org&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6667&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;davidwinter&lt;/span&gt;&lt;span class="nv"&gt;@xxx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xxx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xxx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xxx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Where &lt;code&gt;xxx.xxx.xxx.xxx&lt;/code&gt; is the IP address of my home computer.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve entered this command, entered your password for the SSH connection - leave the Terminal window open. When you&amp;rsquo;re finished, hit Control C to quit SSH.&lt;/p&gt;
&lt;p&gt;In Colloquy, I create a new connection with the following details:
* Chat Server: localhost
* Chat Server Port :6668&lt;/p&gt;
&lt;p&gt;Connect using those details, and then you should be able to join &lt;code&gt;#wmin-compsoc&lt;/code&gt; perfectly.&lt;/p&gt;
&lt;p&gt;Problem solved. I&amp;rsquo;ll try briefly to explain what the &lt;code&gt;ssh&lt;/code&gt; command does.
1. First of all, we want a &lt;code&gt;ssh&lt;/code&gt; connection, but without a shell prompt of the computer we&amp;rsquo;re connecting to. That&amp;rsquo;s what the &lt;code&gt;-N&lt;/code&gt; flag is for.
2. &lt;code&gt;-L&lt;/code&gt; flags this as a local port tunnel.
3. You then first specify the port that you&amp;rsquo;ll use on the computer your using (in my case, my iBook) to tunnel out of the network you&amp;rsquo;re currently connected to.
4. Then the server/IP address you want to access.
5. Then the IP address that you&amp;rsquo;d normally connect to if you weren&amp;rsquo;t having a firewall issue. For IRC, this is 6667.
6. Then you follow all of the above with the SSH connection, which in my case is to my iMac at home. The first part being my username on the computer, and then the IP address.&lt;/p&gt;
&lt;p&gt;Basically, my iMac at home is being used as a bridge between Quakenet and the network at University. The whole connection is secure as it&amp;rsquo;s being encrypted over ssh. So, there&amp;rsquo;s no vulnerability for the University&amp;rsquo;s network technicians to worry about.&lt;/p&gt;
&lt;p&gt;Obviously for this all to work, you need some kind of &amp;lsquo;bridge&amp;rsquo; computer online that you can connect to. Otherwise this isn&amp;rsquo;t going to work.&lt;/p&gt;
&lt;p&gt;Also, this could be used for getting around other kinds of firewall blocked applications. However, remember the connection will be significantly slower as first of all, it&amp;rsquo;s all being encrypted, and secondly because it&amp;rsquo;s having to go via a bridge computer.&lt;/p&gt;
&lt;h4&gt;Meebo!&lt;/h4&gt;
&lt;p&gt;As I said, I could use ssh port tunnelling to connect to MSN, iChat etc. But why bother when I can use the very cool &lt;a href="http://meebo.com"&gt;Meebo&lt;/a&gt;. It&amp;rsquo;s a Web 2.0 application that let&amp;rsquo;s you connect to MSN, AIM, Yahoo! and Jabber instant messaging servers all at the same time, and simply through a web site. No need to download any software. Excellent.&lt;/p&gt;</content><category term="howto"/><category term="irc"/><category term="uni"/></entry><entry><title>Ubuntu 5.10 web server howto</title><link href="https://davidwinter.dev/2006/02/05/ubuntu-5-10-web-server-howto/" rel="alternate"/><published>2006-02-05T00:00:00+00:00</published><updated>2006-02-05T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2006-02-05:/2006/02/05/ubuntu-5-10-web-server-howto/</id><summary type="html">&lt;p&gt;I reinstalled my home server today (well, I actually started yesterday, but today I finished from scratch again) and wrote down what I did. My aim was to have a web server set up using Apache that I could use to host this blog which uses Ruby on Rails. Also …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I reinstalled my home server today (well, I actually started yesterday, but today I finished from scratch again) and wrote down what I did. My aim was to have a web server set up using Apache that I could use to host this blog which uses Ruby on Rails. Also, I wanted to set-up Webmin and Bind so I could manage the DNS stuff from here.&lt;/p&gt;
&lt;p&gt;So, here we go! If you find any errors, or have any problems, leave a comment and I&amp;rsquo;ll try and help.&lt;/p&gt;
&lt;h3&gt;The headache begins&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m assuming that you&amp;rsquo;ve just completed a new default install of Ubuntu 5.10.&lt;/p&gt;
&lt;p&gt;As my space PC/server is up in the loft, and it&amp;rsquo;s freezing up there, the first thing I did was to enable XDMCP on Ubuntu so I could connect to it from my Mac downstairs in my nice warm bedroom. You can read how to do that &lt;a href="/2005/12/08/setting-up-xdmcp-for-mac/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With XDMCP now running, before I can connect to it via my Mac, I set the IP address of the machine to 192.168.0.1 - a nice number that&amp;rsquo;s easy to remember.&lt;/p&gt;
&lt;p&gt;Back in my room I&amp;rsquo;m connected to Ubuntu via XDMCP and it&amp;rsquo;s as if I&amp;rsquo;m sitting up in the loft.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not using XDMCP (and even if you are you should follow this step), you&amp;rsquo;ll want to connect via SSH. Install it using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install ssh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are some packages that are needed that aren&amp;rsquo;t in the default repositories for &lt;code&gt;apt&lt;/code&gt;, so you have to enable them manually. Universe and Multiverse are needed.&lt;/p&gt;
&lt;p&gt;To enable the Universe servers, I did&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/apt/sources.list
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside that file, uncomment the two lines that look something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;deb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://gb.archive.ubuntu.com/ubuntu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;breezy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;universe&lt;/span&gt;
&lt;span class="k"&gt;deb-src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://gb.archive.ubuntu.com/ubuntu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;breezy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;universe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Hit Control O to save and press enter to use the same filename. Then press Control X to close Nano.&lt;/p&gt;
&lt;p&gt;I could probably enable the Multiverse stuff in there too, but as I&amp;rsquo;ve not tested it like that, I&amp;rsquo;ll leave it to exactly how I did it.&lt;/p&gt;
&lt;p&gt;Open up the Synaptic Package Manager
1. Settings
2. Repositories
3. Add
4. Check Multiverse
5. Click OK and let it rescan the servers.&lt;/p&gt;
&lt;p&gt;You can then close Synaptic. &lt;code&gt;apt&lt;/code&gt; is now all set up ready for installing the packages we need.&lt;/p&gt;
&lt;p&gt;Before we start installing the packages we want, do a system update:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Ruby&lt;/h4&gt;
&lt;p&gt;All on one line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install irb libdbm-ruby1.8 libfcgi-ruby1.8 libfcgi0 libgdbm-ruby1.8 libmysql-ruby1.8 libmysqlclient12 libopenssl-ruby1.8 libruby1.8-dbg mysql-common ri ri1.8 ruby1.8-dev ruby
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;MySQL Server&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install mysql-server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;During this install, a Postfix config screen will appear. Select OK and then &amp;ldquo;No configuration&amp;rdquo;.&lt;/p&gt;
&lt;h4&gt;Ruby Gems &amp;amp; Rails&lt;/h4&gt;
&lt;p&gt;This is the standard way of installing ruby applications.&lt;/p&gt;
&lt;p&gt;Need to download it directly from its web site:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;rubyforge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;frs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;5207&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rubygems&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;11.&lt;/span&gt;&lt;span class="n"&gt;tgz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then extract it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tar xvfz rubygems-0.8.11.tgz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Move into the extracted directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd rubygems-0.8.11
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Run the setu-p program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ruby1.8 setup.rb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Update all installed gems on the system:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo gem update --system
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now that Ruby Gems is installed, we can install Rails.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo gem install rails -y
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Apache 2&lt;/h4&gt;
&lt;p&gt;Next is the web server I&amp;rsquo;m using. Apache 2. The following command will install Apache 2, FastCGI, FCGI, PHP 5 with MySQL functionality. PHP isn&amp;rsquo;t needed for Ruby or Rails, but I&amp;rsquo;m including it so that I can run PHP apps&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install apache2 libapache2-mod-fcgid libapache2-mod-fastcgi libapache2-mod-php5 php5-mysql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once that&amp;rsquo;s done, we&amp;rsquo;ll need to enable the Apache mods we&amp;rsquo;ll be using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo a2enmod fcgid
sudo a2enmod fastcgi
sudo a2enmod rewrite
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll notice I&amp;rsquo;ve installed two different types of Fast CGI. That&amp;rsquo;s because at some point I want to try them both out. However, at the moment, I&amp;rsquo;ve only had success with getting FastCGI working decently.&lt;/p&gt;
&lt;p&gt;Restart Apache to make sure all is well.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;FastCGI&lt;/h4&gt;
&lt;p&gt;I thought FastCGI would have been installed after doing the libapache2-mod-fastcgi - but for some reason, you have to install it manually.&lt;/p&gt;
&lt;p&gt;In order to configure and build from the source files, you need to download some basic files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install build-essential
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, grab the FastCGI files from the web site:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;wget http://fastcgi.com/dist/fcgi-2.4.0.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Extract:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tar xvfz fcgi-2.4.0.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Move into the directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd fcgi-2.4.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Configure the installer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./configure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, that is all of the Apache and FastCGI files installed. Later, we&amp;rsquo;ll need to configure it all.&lt;/p&gt;
&lt;h4&gt;Webmin&lt;/h4&gt;
&lt;p&gt;Webmin is ugly, but it works, and it lets us configure Apache and the Nameserver easily.&lt;/p&gt;
&lt;p&gt;Go to http://www.webmin.com/ and download the latest version of webmin in tar.gz format.&lt;/p&gt;
&lt;p&gt;Once downloaded, extract it (filename may vary depending on the version you download):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tar xvfz webmin-1.260.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Move into the directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd webmin-1.260
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Run the set-up program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ./setup.sh /usr/local/webmin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can use the default settings for this, or change them if you know what you&amp;rsquo;re doing. Be sure to set a password you can remember.&lt;/p&gt;
&lt;p&gt;At the end of the set-up you&amp;rsquo;ll be given an address to use to connect to webmin. Remember this! and go to it straight away and login.&lt;/p&gt;
&lt;p&gt;Do the following to configure Webmin to work with Apache:
1. At the top, click on the &amp;ldquo;Servers&amp;rdquo; link.
2. Select Apache Webserver.
3. Select Module Config.
4. Set the following values:
    * Apache Server Root - /etc/apache2
    * Path to httpd executable - /usr/sbin/apache2
    * Path to httpd.conf - /etc/apache2/httpd.conf
    * Command to start Apache - /etc/init.d/apache2 start
    * Command to stop Apache - /etc/init.d/apache2 stop&lt;/p&gt;
&lt;p&gt;Save these settings.&lt;/p&gt;
&lt;h4&gt;Nameserver&lt;/h4&gt;
&lt;p&gt;I&amp;rsquo;m no DNS expert, so this is very vague and I suggest you go read a howto on DNS&amp;hellip; &lt;a href="http://rimuhosting.com/support/bindviawebmin.jsp"&gt;here&amp;rsquo;s one&lt;/a&gt; I used to complete this part.&lt;/p&gt;
&lt;p&gt;This will be different depending on your set-ups. For me, I have my domain name pointing to my web server in America that hosts http://commanderbond.net&lt;/p&gt;
&lt;p&gt;On the server, there, I have the DNS pointing to my Internet IP at home, here in the UK.&lt;/p&gt;
&lt;p&gt;The nameserver I&amp;rsquo;m using is Bind.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt-get install bind9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once that&amp;rsquo;s installed, we need to configure it in Webmin.
1. Click the &amp;ldquo;Servers&amp;rdquo; link.
2. Select BIND DNS Server.
3. A message will appear about a configuration file. Select the 3rd option &amp;ldquo;Setup as an internet name server, but use Webmin&amp;rsquo;s older root server information&amp;rdquo;
4. Create a Master Zone and enter the following details:
    * Domain Name - yourdomain.com
    * Email - you@anemail.com
5. Click on &amp;ldquo;Create&amp;rdquo;.
6. Click on the &amp;ldquo;Address&amp;rdquo; link.
7. Create a new Address record using the following:
    * Name - yourdomain.com. (including the trailing dot)
    * Address - your Internet IP address
8. Click on &amp;ldquo;Create&amp;rdquo;.
9. Go to the Module Index.
10. Click on &amp;ldquo;Apply Changes&amp;rdquo;.&lt;/p&gt;
&lt;h4&gt;Set-up your web site&lt;/h4&gt;
&lt;p&gt;You&amp;rsquo;ll need somewhere to store your web site files, so I suggest to first of all create a &lt;code&gt;public_html&lt;/code&gt; directory in your user directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir ~/public_html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we&amp;rsquo;ll create a test HTML file to check all is working so far.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nano ~/public_html/index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside it put the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hopefully&lt;span class="w"&gt; &lt;/span&gt;you&lt;span class="w"&gt; &lt;/span&gt;can&lt;span class="w"&gt; &lt;/span&gt;see&lt;span class="w"&gt; &lt;/span&gt;this...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file using Control O and then Control X to quit Nano.&lt;/p&gt;
&lt;p&gt;Now, set the permissions of the file so it&amp;rsquo;s visible to the world:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;chmod 644 ~/public_html/index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In Webmin, go to the Apache configuration.&lt;/p&gt;
&lt;p&gt;Create a new Virtual Server with the following:
* Document Root - home/yourusername/public_html
* Server Name - yourdomain.com&lt;/p&gt;
&lt;p&gt;Save the settings. Now restart Apache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now visit http://yourdomain.com/~yourusername/ and you should see:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hopefully you can see this&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If so, excellent! If not, hmmm&amp;hellip; maybe you didn&amp;rsquo;t follow everything? or I made a mistake somewhere&amp;hellip; leave a comment below.&lt;/p&gt;
&lt;p&gt;Take a 5 minute break!&lt;/p&gt;
&lt;p&gt;Refreshed? Right. Moving on&amp;hellip;&lt;/p&gt;
&lt;h4&gt;phpMyAdmin for MySQL management&lt;/h4&gt;
&lt;p&gt;Go to http://www.phpmyadmin.net/home_page/index.php and download the latest stable release of phpMyAdmin in tar.gz format.&lt;/p&gt;
&lt;p&gt;Extract:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tar xvfz phpMyAdmin-2.7.0-pl2.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Move the directory to some place helpful:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mv phpMyAdmin-2.7.0-pl2 ~/phpmyadmin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Move into that directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ~/phpmyadmin/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create a new configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cp config.default.php config.inc.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Change the authentication mode to http&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gedit config.inc.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Change this line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;Servers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;auth_type&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&amp;hellip;to this line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;Servers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;auth_type&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file.&lt;/p&gt;
&lt;p&gt;Back in the command line, we need to set the root password, because by default, there isn&amp;rsquo;t one!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mysql -u root
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll then enter the MySQL console. Enter the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;UPDATE mysql.user SET Password=PASSWORD(&amp;#39;newpasswordhere&amp;#39;) WHERE User=&amp;#39;root&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will set the root password. Now flush the privileges:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;FLUSH PRIVILEGES;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now exit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, we want phpMyAdmin accessible on the server &amp;lsquo;globally&amp;rsquo;. So that it doesn&amp;rsquo;t matter what address we&amp;rsquo;re using, we&amp;rsquo;ll still be able to access it.&lt;/p&gt;
&lt;p&gt;In Webmin, under Apache Webserver:
1. Select &amp;ldquo;Default Server&amp;rdquo;
2. Aliases and Redirects
3. Under &amp;ldquo;Document directory aliases&amp;rdquo; enter &lt;code&gt;/phpmyadmin/&lt;/code&gt; into the first text box, and &lt;code&gt;/home/davidwinter/phpmyadmin/&lt;/code&gt; into the box to the right of that one.&lt;/p&gt;
&lt;p&gt;Save, and in the Terminal restart apache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Go to http://yourdomain.com/phpmyadmin/&lt;/p&gt;
&lt;p&gt;Login in using &amp;ldquo;root&amp;rdquo; and the password you set in the MySQL console.&lt;/p&gt;
&lt;p&gt;You can do any MySQL configuration here. For me, I restored my Typo database for this blog from a backup.&lt;/p&gt;
&lt;h4&gt;FastCGI configuration with a Rails application&lt;/h4&gt;
&lt;p&gt;This part is what gets a Rails app running really fast.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll need to configure the FastCGI config file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/apache2/mods-enabled/fastcgi.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here is my config file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;IfModule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mod_fastcgi.c&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;#FastCgiWrapper&lt;span class="w"&gt; &lt;/span&gt;/usr/lib/apache2/suexec2
&lt;span class="w"&gt;  &lt;/span&gt;FastCgiIpcDir&lt;span class="w"&gt; &lt;/span&gt;/var/lib/apache2/fastcgi
&lt;span class="w"&gt;  &lt;/span&gt;FastCgiConfig&lt;span class="w"&gt; &lt;/span&gt;-maxClassProcesses&lt;span class="w"&gt; &lt;/span&gt;2&lt;span class="w"&gt; &lt;/span&gt;-maxProcesses&lt;span class="w"&gt; &lt;/span&gt;2&lt;span class="w"&gt; &lt;/span&gt;-minProcesses&lt;span class="w"&gt; &lt;/span&gt;2&lt;span class="w"&gt; &lt;/span&gt;-processSlack&lt;span class="w"&gt; &lt;/span&gt;2
&lt;span class="w"&gt;  &lt;/span&gt;FastCgiServer&lt;span class="w"&gt; &lt;/span&gt;/home/davidwinter/typo/public/dispatch.fcgi&lt;span class="w"&gt; &lt;/span&gt;-idle-timeout&lt;span class="w"&gt; &lt;/span&gt;120&lt;span class="w"&gt; &lt;/span&gt;-processes&lt;span class="w"&gt; &lt;/span&gt;2&lt;span class="w"&gt; &lt;/span&gt;-initial-env&lt;span class="w"&gt; &lt;/span&gt;RAILS_ENV=production
&lt;span class="nt"&gt;&amp;lt;/IfModule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The following line of the above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;FastCgiServer /home/davidwinter/typo/public/dispatch.fcgi -idle-timeout 120 -processes 2 -initial-env RAILS_ENV=production
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Is important. You need to specifiy a line like this for each Rails app you&amp;rsquo;ll be using under FastCGI.&lt;/p&gt;
&lt;p&gt;Now, in your Rails application directory check that in &lt;code&gt;public/.htaccess&lt;/code&gt; has this line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;AddHandler fastcgi-script .fcgi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And, that in the rewrite rules section, it has this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&amp;hellip;instead of:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice &lt;code&gt;.fcgi&lt;/code&gt; instead of &lt;code&gt;.cgi&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s about it!&lt;/p&gt;
&lt;p&gt;Give Apache one final restart:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And you should now have everything working.&lt;/p&gt;
&lt;p&gt;As I said, any problems, leave a comment and I&amp;rsquo;ll try and help.&lt;/p&gt;</content><category term="apache"/><category term="howto"/><category term="mysql"/><category term="rails"/><category term="ruby"/><category term="ubuntu"/></entry><entry><title>Java foreach loop</title><link href="https://davidwinter.dev/2005/12/08/java-foreach-loop/" rel="alternate"/><published>2005-12-08T00:00:00+00:00</published><updated>2005-12-08T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2005-12-08:/2005/12/08/java-foreach-loop/</id><summary type="html">&lt;p&gt;Coming from a PHP background, it&amp;rsquo;s always annoyed me that I can&amp;rsquo;t use something as simple as a &lt;a href="http://uk.php.net/foreach"&gt;foreach()&lt;/a&gt; loop in my C++/Java applications.&lt;/p&gt;
&lt;p&gt;However, with a recent lecture on the Collections API and Generics, that&amp;rsquo;s all changed as I&amp;rsquo;ve found the Java equivalent!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Vector …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Coming from a PHP background, it&amp;rsquo;s always annoyed me that I can&amp;rsquo;t use something as simple as a &lt;a href="http://uk.php.net/foreach"&gt;foreach()&lt;/a&gt; loop in my C++/Java applications.&lt;/p&gt;
&lt;p&gt;However, with a recent lecture on the Collections API and Generics, that&amp;rsquo;s all changed as I&amp;rsquo;ve found the Java equivalent!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myVector&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myVector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which is the same as doing something nasty like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myVector&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myVector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myVector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Saves a ton of time.&lt;/p&gt;</content><category term="howto"/><category term="java"/></entry><entry><title>Setting up XDMCP for Mac</title><link href="https://davidwinter.dev/2005/12/08/setting-up-xdmcp-for-mac/" rel="alternate"/><published>2005-12-08T00:00:00+00:00</published><updated>2005-12-08T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2005-12-08:/2005/12/08/setting-up-xdmcp-for-mac/</id><summary type="html">&lt;p&gt;I just finished setting up a spare PC I had with &lt;a href="http://ubuntulinux.org" title="Ubuntu"&gt;Ubuntu&lt;/a&gt; on it. Thing is, it&amp;rsquo;s damn noisy so I want it stuffed up in the loft out of the way. This is fine because I can remote log-in to it using VNC, right? The answer would be …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I just finished setting up a spare PC I had with &lt;a href="http://ubuntulinux.org" title="Ubuntu"&gt;Ubuntu&lt;/a&gt; on it. Thing is, it&amp;rsquo;s damn noisy so I want it stuffed up in the loft out of the way. This is fine because I can remote log-in to it using VNC, right? The answer would be yes if I made sure I was actually logged into my account on the machine - but that would mean having to get a monitor/keyboard/mouse up there to do so.&lt;/p&gt;
&lt;p&gt;Alternative? XDMCP. It&amp;rsquo;s kind of like VNC, but allows you to connect to your machine if no one is logged in. I don&amp;rsquo;t know the technical what&amp;rsquo;s going on in the background, but I&amp;rsquo;ve managed to get this working on my Mac.&lt;/p&gt;
&lt;h3&gt;Enable XDMCP on Ubuntu&lt;/h3&gt;
&lt;p&gt;First of all you&amp;rsquo;ll need to enable XDMCP access on the Ubuntu machine. This is really simple to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;System&lt;/code&gt; &amp;gt; &lt;code&gt;Administration&lt;/code&gt; &amp;gt; &lt;code&gt;Login Screen Setup&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Enter your administration password&lt;/li&gt;
&lt;li&gt;Under the Security tab, &lt;code&gt;Enable XDMCP&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;You can then &lt;code&gt;Close&lt;/code&gt; the window&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;X11 on Mac OS X&lt;/h3&gt;
&lt;p&gt;When I upgraded to &lt;a href="http://www.apple.com/macosx/" title="Mac OS X Tiger"&gt;Tiger&lt;/a&gt;, I didn&amp;rsquo;t install &lt;a href="http://www.apple.com/macosx/features/x11/" title="X11"&gt;X11&lt;/a&gt; which you&amp;rsquo;ll need to pull this all off. Fear not - it&amp;rsquo;s easy to install.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Just slide in your Tiger install CD.&lt;/li&gt;
&lt;li&gt;When it&amp;rsquo;s in, scroll down the Finder window slightly and you&amp;rsquo;ll see Optional Packages or something similar.&lt;/li&gt;
&lt;li&gt;Run that app and install X11.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Connecting&lt;/h3&gt;
&lt;p&gt;Once X11 is installed, and XDMCP is enabled on Ubuntu, all that&amp;rsquo;s left is to actually connect.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;Terminal.app&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Enter in &lt;code&gt;/usr/X11R6/bin/X -query XXX.XXX.XXX.XX&lt;/code&gt; where XXX.XXX.XXX.XXX is the IP of the Ubuntu machine&lt;/li&gt;
&lt;li&gt;A new app will open named &lt;code&gt;Xquartz&lt;/code&gt; and a few seconds after you should see the Ubuntu login screen appear.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that&amp;rsquo;s all there is to it! You&amp;rsquo;re then able to login and work on Ubuntu as if you were actually sitting in front of it. Expose even works which is really handy.&lt;/p&gt;
&lt;p&gt;The only problem I&amp;rsquo;ve had is that it&amp;rsquo;s sometimes hard to switch between windows. If you&amp;rsquo;re having problems, just click on the &lt;code&gt;Xquartz.app&lt;/code&gt; icon in the dock to get Ubuntu back.&lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re finished, log out in Ubuntu and then switch to &lt;code&gt;Terminal.app&lt;/code&gt; in OS X and hit &lt;code&gt;CONTROL + C&lt;/code&gt; to quit &lt;code&gt;Xquartz.app&lt;/code&gt;.&lt;/p&gt;</content><category term="howto"/><category term="mac"/><category term="ubuntu"/></entry><entry><title>Sorting a Vector using Collections.sort()</title><link href="https://davidwinter.dev/2005/12/08/sorting-a-vector-using-collections-sort/" rel="alternate"/><published>2005-12-08T00:00:00+00:00</published><updated>2005-12-08T00:00:00+00:00</updated><author><name>David Winter</name></author><id>tag:davidwinter.dev,2005-12-08:/2005/12/08/sorting-a-vector-using-collections-sort/</id><summary type="html">&lt;p&gt;&lt;code&gt;Collections.sort()&lt;/code&gt; allows you to sort a &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/collections/index.html"&gt;Collections&lt;/a&gt; framework that is inherited from the &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/List.html"&gt;List&lt;/a&gt; class. The &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Vector.html"&gt;Vector&lt;/a&gt; class is, so that&amp;rsquo;s great!&lt;/p&gt;
&lt;p&gt;For demonstrations sake, I&amp;rsquo;ll be using a Vector that stores some products. I want to sort the products by price. I&amp;rsquo;ll assume you&amp;rsquo;d …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;code&gt;Collections.sort()&lt;/code&gt; allows you to sort a &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/collections/index.html"&gt;Collections&lt;/a&gt; framework that is inherited from the &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/List.html"&gt;List&lt;/a&gt; class. The &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Vector.html"&gt;Vector&lt;/a&gt; class is, so that&amp;rsquo;s great!&lt;/p&gt;
&lt;p&gt;For demonstrations sake, I&amp;rsquo;ll be using a Vector that stores some products. I want to sort the products by price. I&amp;rsquo;ll assume you&amp;rsquo;d include setter and getter methods for each data member rather than declaring them public. But again for ease of this tutorial, I&amp;rsquo;ve just made them &lt;code&gt;public&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;public class Product
{
    public double price;
    public String name;

    public Product()
    {
        this.price(0.0);
        this.name(&amp;quot;&amp;quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;rsquo;d create a Vector of Products by using&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Vector&amp;lt;Product&amp;gt; products = new Vector&amp;lt;Product&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So that we can sort the vector, we need a way of telling &lt;code&gt;Collections.sort()&lt;/code&gt; how to compare our Products. For example, how it can tell that ÃƒÆ’Ã¢â‚¬Å¡Ãƒâ€šÃ‚Â£1.99 is greater than ÃƒÆ’Ã¢â‚¬Å¡Ãƒâ€šÃ‚Â£0.99. I&amp;rsquo;ve already chosen that we want to sort by price.&lt;/p&gt;
&lt;p&gt;In order for us to do this, we need our Product class to implement the interface &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Comparable.html"&gt;&lt;code&gt;Comparable&lt;/code&gt;&lt;/a&gt;. This interface contains only one method - &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Comparable.html#compareTo(T)"&gt;&lt;code&gt;compareTo()&lt;/code&gt;&lt;/a&gt; that must be implemented in our Product class. It&amp;rsquo;s this function that &lt;code&gt;Collections.sort()&lt;/code&gt; uses.&lt;/p&gt;
&lt;p&gt;So, how exactly do we do that?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Comparable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// other functions in this class&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;compareTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;compareTo()&lt;/code&gt; will return an integer value that represents the comparison between two Product objects. &lt;code&gt;-1&lt;/code&gt; will represent a Product that is less than the one we&amp;rsquo;re checking against. &lt;code&gt;0&lt;/code&gt; will represent an Product of equal values (in our case, that have the same price). And finally &lt;code&gt;1&lt;/code&gt; will represent an Product that is more than the one we&amp;rsquo;re checking.&lt;/p&gt;
&lt;p&gt;In order to perform the check we need to compare the prices. These are represented in our class as &lt;code&gt;double&lt;/code&gt;. The class Double already implements the &lt;code&gt;Comparable&lt;/code&gt; interface, so that means we know that &lt;code&gt;compareTo()&lt;/code&gt; is a method of the Double class. So we&amp;rsquo;re going to use that to compare our prices.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;public int compareTo(Object o)
{
    Product e = (Product) o;

    int result = this.price.compareTo(e.price);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What this is doing is first of all getting the price of the Product object. This returns a double. We then apply the &lt;code&gt;compareTo()&lt;/code&gt; method to that returned the double with the object given in the parameter. We call &lt;code&gt;e.price&lt;/code&gt; which returns the double of the price for the compare object.&lt;/p&gt;
&lt;p&gt;After doing this, we get an integer returned and stored into &lt;code&gt;result&lt;/code&gt;. We need to check what this value is.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;compareTo&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;o&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
{
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;Product&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Product&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;o&lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;this&lt;/span&gt;.&lt;span class="nv"&gt;price&lt;/span&gt;.&lt;span class="nv"&gt;compareTo&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;.&lt;span class="nv"&gt;price&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;{
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;}
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;{
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;}
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;{
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If the result is less than 0, that means that the price of the current Product object is less than the one we&amp;rsquo;re checking against. 0 will mean that the prices are equal. And more than 1 means the price is more than the current Product.&lt;/p&gt;
&lt;p&gt;So based on the result value, we return a new integer value that represents the comparison between two Products. Less than 0 if the object is less than the one being compared. 0 if they are equal, and more than if it is more than the compared object.&lt;/p&gt;
&lt;p&gt;At this stage we&amp;rsquo;ve implemented the &lt;code&gt;Comparable&lt;/code&gt; interface for our Product class. This now means our Product objects can be compared against one another based on their prices.&lt;/p&gt;
&lt;p&gt;Now we actually want to sort our Vector. We&amp;rsquo;ll need to create the sort method.&lt;/p&gt;
&lt;p&gt;In this example, I&amp;rsquo;m extending the Vector class:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProductList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProductList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProductList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is where &lt;code&gt;Collections.sort()&lt;/code&gt; comes in. Now that our Product objects can be compared, the &lt;code&gt;Collections.sort()&lt;/code&gt; static method can access our vector and compare the objects in it and re-sort it accordingly.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ProductList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sort&lt;/span&gt;&lt;span class="ss"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;{
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;ProductList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sorted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ProductList&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;this&lt;/span&gt;.&lt;span class="nv"&gt;clone&lt;/span&gt;&lt;span class="ss"&gt;()&lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;Collections&lt;/span&gt;.&lt;span class="nv"&gt;sort&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sorted&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sorted&lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will then return an updated ProductList object (which is the Vector storing our Products).&lt;/p&gt;
&lt;p&gt;Bingo.&lt;/p&gt;</content><category term="howto"/><category term="java"/></entry></feed>