scurker.com WilsonClearing a Path for Offlinehttps://scurker.com2018-06-05T00:00:00+00:00<html><head></head><body><p>I&apos;ve long known the benefits of service workers, but had not made the push to implement one for my own site. With the recent <a href="">change in Safari</a> finally taking service workers to task, it was time to hop aboard the service worker train myself. Now if you visit my site, select pages will be available with offline viewing.</p> <p>As of <a href="">June 2018</a>, 83% of global users have some form of service worker support so there&apos;s little reason not to have one especially as mobile connectivity becomes more pervasive. If you&apos;ve made it this far and still don&apos;t know what a service worker is, <a href="">Google has an excellent primer</a> all about the inner workings of service workers.</p> <h2 id="a-worker-to-build"><a class="anchor-link" aria-hidden="true" href="#a-worker-to-build"></a>A worker to build</h2> <p>I build my blog on top of <a href="">metalsmith</a>, and there was a couple of key aspects I wanted to build into my service worker:</p> <ul> <li>Increment cache version for each static site build</li> <li>Have my service worker automatically include built static assets</li> <li>Have my offline page list previously visited offline pages</li> </ul> <p>I am not going to suggest the path that I took towards the end result is one that should be similarly followed, but wanted to outline the steps that led me there.</p> <h3 id="versioning"><a class="anchor-link" aria-hidden="true" href="#versioning"></a>Versioning</h3> <p>Whenever a service worker changes, a new version is downloaded and installed. To ensure that the browser&apos;s cache is up to date we want the service worker to have a new version key to be able to clear out older requests.</p> <p>My static site doesn&apos;t change frequently, so having a cache version based on date seems relatively safe. Using <a href="">rollup</a> in combination with <a href="">rollup-plugin-replace</a> I can replace <code>CACHE_VERSION</code> with the current date&apos;s version string.</p> <pre><code><span class="selector-tag">replace</span>({ <span class="attribute">CACHE_VERSION</span>: JSON.<span class="built_in">stringify</span>( new Date().<span class="built_in">toISOString</span>().<span class="built_in">split</span>(<span class="string">&apos;T&apos;</span>)[<span class="number">0</span>].<span class="built_in">replace</span>(/-/g, <span class="string">&apos;&apos;</span>) ) }) </code></pre><h3 id="including-assets"><a class="anchor-link" aria-hidden="true" href="#including-assets"></a>Including Assets</h3> <p>Similarly to versioning above, I utilize rollup to scan my assets folder to match static assets and replace <code>STATIC_ASSETS</code> with the array of assets to pre-cache in the service worker on install.</p> <pre><code>replace({ <span class="attr">STATIC_ASSETS</span>: <span class="built_in">JSON</span>.stringify([ ...glob.sync(<span class="string">&apos;assets/**/*&apos;</span>, { <span class="attr">cwd</span>: path.resolve(__dirname, <span class="string">&apos;build&apos;</span>), <span class="attr">nodir</span>: <span class="literal">true</span> }).map(<span class="function"><span class="params">file</span> =&gt;</span> <span class="string">`/<span class="subst">${file}</span>`</span>) ], <span class="literal">null</span>, <span class="number">2</span>) }) </code></pre><h3 id="listing-offline-posts"><a class="anchor-link" aria-hidden="true" href="#listing-offline-posts"></a>Listing offline posts</h3> <p>For listing offline posts, I&apos;m utilizing <a href="">metalsmith middleware</a> to generate <a href="">json metadata</a> about my site to pre-cache in my service worker to later compare cached requests against known pages. I could just list visited offline posts by their url, but by generating and pre-caching metadata about any particular page, I can include page titles and dates to list <a href="/offline">/offline</a>.</p> <pre><code class="lang-js"><span class="keyword">const</span> isOfflinePage = <span class="built_in">document</span>.body.classList.contains(<span class="string">&apos;offline-page&apos;</span>); <span class="keyword">if</span> (<span class="built_in">window</span>.caches &amp;&amp; isOfflinePage) { caches.keys() .then(<span class="function"><span class="params">keys</span> =&gt;</span> { <span class="keyword">return</span> <span class="built_in">Promise</span>.all([<span class="function"><span class="params">c</span> =&gt;</span> c.keys()), fetch(<span class="string">&apos;/pages.json&apos;</span>).then(<span class="function"><span class="params">res</span> =&gt;</span> res.json()) ]); }) .then(<span class="function">(<span class="params">[ requests, pages ]</span>) =&gt;</span> { <span class="comment">// match the requests in the cache against known posts</span> <span class="keyword">let</span> posts = pages.filter(<span class="function">(<span class="params">{ type }</span>) =&gt;</span> type === <span class="string">&apos;post&apos;</span>) , matchedPosts = posts.filter( <span class="function"><span class="params">post</span> =&gt;</span> requests.find(<span class="function"><span class="params">req</span> =&gt;</span> <span class="keyword">new</span> URL(req.url).pathname.indexOf(post.path) !== <span class="number">-1</span>) ); <span class="keyword">let</span> offlineContainer = <span class="built_in">document</span>.querySelector(<span class="string">&apos;.offline-posts&apos;</span>); <span class="keyword">if</span>(matchedPosts.length) { <span class="comment">// display offline posts on the page</span> } <span class="keyword">else</span> { offlineContainer.remove(); } }); } </code></pre> <h2 id="there-are-many-service-workers-this-one-is-mine"><a class="anchor-link" aria-hidden="true" href="#there-are-many-service-workers-this-one-is-mine"></a>There are many service workers &#x2013; this one is mine</h2> <p>Beyond the methods outline above, my service worker isn&apos;t a particularly specialized affair. Following patterns from <a href="">Jake Archibald&apos;s offline cookbook</a>, <a href="">pre-caches assets on install</a>, <a href="">removes old caches on activate</a>, and serving content with a <a href="">network first with cache fallback</a> pattern.</p> <p>For a full picture, you can view my service worker scripts below.</p> <ul> <li><a href=""><code>sw.js</code></a> <em>prebuild</em></li> <li><a href=""><code>sw.js</code></a> <em>postbuild</em></li> <li><a href=""><code>rollup.sw.config.js</code></a></li> </ul> <h2 id="thoughts-to-improve"><a class="anchor-link" aria-hidden="true" href="#thoughts-to-improve"></a>Thoughts to improve</h2> <p>These are only my first steps towards a path for offline, but there are certain areas of improvement I could see. Service worker asset responses could follow a <a href="">cache with network fallback</a> recipe since my assets aren&apos;t likely to change frequently. Or, if I was to uniquely identify assets with some sort of asset hash could place assets into a more permanent cache only expiring assets if a new version is received.</p> </body></html>Interesting talks at JSConf 2015https://scurker.com2015-05-31T00:00:00+00:00<html><head></head><body><p>This is my second year of being able to attend JSConf and feel fortunate to be able to listen and interact with so many awesome people in the community. This is mostly a brain dump of some of the topics I found interesting at JSConf, but obviously isn&apos;t every talk or speaker since I couldn&apos;t attend every session. Hopefully, some others can benefit from some of the knowledge I gained - or find some interesting people to follow in the community.</p> <h2 id="js-accessibility-and-js-side-by-side-felipe-de-albuquerque"><a class="anchor-link" aria-hidden="true" href="#js-accessibility-and-js-side-by-side-felipe-de-albuquerque"></a>JS Accessibility and JS: side-by-side - <a href="">Felipe de Albuquerque</a></h2> <p>This was an interesting talk on accessibility because the talk itself wasn&apos;t presented in English. Felipe gave a few examples of why accessibility is important:</p> <ul> <li>650 million people have some some kind of disability</li> <li>Kids can control websites through voice before they can read, so having voice control would allow young kids to navigate</li> <li>The internet should be inclusive of everyone</li> <li>Based on research, <a href="">JAWS</a> is one of the most popular screen readers</li> </ul> <p>One of the biggest issues we have in the community is the lack of developer knowledge with WAI-ARIA attributes. ARIA attributes are something that are ready to be implemented <em>today</em>, and as a community we should be concerned about making our applications accessible to everyone.</p> <h2 id="communicate-all-the-things-kyle-tyacke"><a class="anchor-link" aria-hidden="true" href="#communicate-all-the-things-kyle-tyacke"></a>Communicate All the Things - <a href="">Kyle Tyacke</a></h2> <p>Building the web with WebRTC. If you&apos;ve ever used Amazon Mayday, or Google Hangouts you&apos;ve used WebRTC. WebRTC is similar to web sockets, but uses peer-to-peer connections instead of communicating with a server.</p> <p><a href="">Apollo</a> is a JavaScript library built on <a href="">respoke</a> that helps to handle those peer-to-peer connections. From there you can create peer-to-peer chat or video connections directly in your application.</p> <h2 id="async-programing-in-es7-es2016-jafar-husain"><a class="anchor-link" aria-hidden="true" href="#async-programing-in-es7-es2016-jafar-husain"></a>Async Programing in <del>ES7</del> ES2016 - <a href="">Jafar Husain</a></h2> <p>How do we make async easier? What if you could write async programs without any callbacks at all? What if waiting was just as easy as creating blocking functions?</p> <p>With ES2016, you can use generators to write blocking or asynchronous code exactly the same:</p> <pre><code class="lang-javascript"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>{ <span class="keyword">var</span> bar = <span class="keyword">await</span> foobar(); <span class="keyword">return</span> bar; } </code></pre> <p>Currently ES2016 is in the draft stage, but it&apos;s expected to be part of the standard.</p> <p>This was a great talk that helped explain some of the features <del>ES5</del>ES2015 on generators and how they differ from iterators. One great point is that iterators are used for one-way functional communication, while generators are used for two-way functional communication. By calling <code>;value&quot;)</code> on a generator, you can push values to a generator function.</p> <p>It&apos;s hard to explain everything in short, but Jafar has created a repository that goes into further detail on <a href="">generators, observables, and async generators</a>.</p> <h2 id="knitting-for-javascript-mariko-kosaka"><a class="anchor-link" aria-hidden="true" href="#knitting-for-javascript-mariko-kosaka"></a>Knitting for JavaScript - <a href="">Mariko Kosaka</a></h2> <p>Apparently there&apos;s a &quot;Github&quot; for knitters, <a href="">Ravelry</a>.</p> <p>Code for knitting.</p> <pre><code><span class="built_in">R0</span> : <span class="built_in">k5</span> <span class="built_in">R1</span>-<span class="number">3</span> : <span class="built_in">k2</span>, m1, k until <span class="number">2</span> sts remain, m1, <span class="built_in">k2</span> <span class="built_in">R4</span> : <span class="built_in">k2</span>, m1, <span class="built_in">k1</span>, m1, k until <span class="number">3</span> sts remain, m1, <span class="built_in">k1</span>, m1, <span class="built_in">k2</span> Repeat <span class="built_in">R1</span>-<span class="number">4</span> for <span class="number">10</span> <span class="built_in">times</span> </code></pre><p>That looks like something that could easily be created in javascript.</p> <p>Mariko took two seemingly unrelated topics and merged them together to create something amazing and fascinating. This was a great talk that helped expose how JavaScript could be used for things that no one would really expect.</p> <p>Kariko plans on putting up some of her code on Github at <a href="">electroknit</a> and <a href="">color-mixer</a>.</p> <h2 id="30-minutes-or-less-the-magic-of-automated-accessibility-testing-marcy-sutton"><a class="anchor-link" aria-hidden="true" href="#30-minutes-or-less-the-magic-of-automated-accessibility-testing-marcy-sutton"></a>30 Minutes or Less: The Magic of Automated Accessibility Testing - <a href="">Marcy Sutton</a></h2> <p>What are some the the accessibility basics you should be aware of?</p> <ul> <li>Alternative text</li> <li>Document structure &amp; hierarchy</li> <li>HTML Semantics</li> <li>Keyboard interactivity</li> <li>Color contrast</li> <li>Focus management</li> </ul> <p>Let the tooling do the heavy lifting for you! Tools can help you identify some of your accessibility issues.</p> <p>In Chrome Canary, you can enable <a href="">accessibility developer tools</a> that will allow you to run audits on your page to help find those issues.</p> <ul> <li><a href="">A11Y (Ally)</a> - run accessibility audits against a site.</li> <li><a href="">Protractor + Accessibility Plugin</a> - end to end testing accessibility plugin Angular JS</li> </ul> </body></html>In Harmony with Javascript - ES6, Javascript, and Youhttps://scurker.com2015-04-25T00:00:00+00:00<html><head></head><body><p>I have been wanting to give a talk on some of the exciting features of ES6 Harmony - and how you could start utilizing certain components of ES6 today, and <a href="">BarCamp Birmingham</a> was a great venue to introduce this talk.</p> <p>It&apos;s hard to talk about <a href="">all the great features</a> that are a part of ES6, but I mainly wanted to touch on the ones that are usable today and the various strategies for implementing ES6 features as part of your code.</p> <p>Want to know the short of it? For browsers, it&apos;s fairly safe to use many of the ES6 features outlined below with the right polyfill. For node or io, io has better support out of the box while node 0.11.x+ requires specific ES6 feature flags enabled.</p> <div class="video-wrapper"> <iframe src="//" width="576" height="420" scrolling="no" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen></iframe> </div> <p>Important links</p> <ul> <li><a href="">ES6 Complete Feature Set</a></li> <li><a href="">Internet Explorer ES6 Support</a> on</li> <li><a href="">ES6 Compatibility Tables</a> including browsers and javascript engines</li> <li><a href="">core-js</a>, various polyfills for ES5, ES6, and ES7</li> <li><a href="">es6-shim</a> compatibility shims for ES6</li> <li><a href="">Babel</a> a transpiler for compiling ES6 code to ES5</li> <li><a href="">Traceur</a> compiles ES6 as well as some features</li> </ul> <p>You can view the <a href="">full sets of slides over at</a>.</p> </body></html>Automated Deploys with Travis CIhttps://scurker.com2015-03-09T00:00:00+00:00<html><head></head><body><p>If you read my previous post about <a href="/remote-deployments-with-git">remote deployments with git</a>, you should have a good idea on how you can deploy with a simple git push. This method works fine if you only work from one computer but starts to be a little more difficult if you want to use other devices (such as an tablet or phone) and potentially want to write posts or content directly on Github.</p> <h2 id="bring-in-travis-ci"><a class="anchor-link" aria-hidden="true" href="#bring-in-travis-ci"></a>Bring in Travis CI</h2> <p>If you aren&apos;t using a CI (continuous integration) tool as part of your workflow, you should be! I&apos;ve started to become a big fan of <a href="">Travis CI</a> because it&apos;s easy to setup, integrates easily with GitHub, and runs on a <a href="">number of different languages</a>. And best of all, it&apos;s free<sup>*</sup>!</p> <p><small>* for open source projects</small></p> <p>I use Travis to centralize my pushes so that I no longer have to have setup remote pushes from my local computer directly to my remote server to update content, but rather push directly to a Github branch and let Travis take care of the rest.</p> <h2 id="getting-started"><a class="anchor-link" aria-hidden="true" href="#getting-started"></a>Getting Started</h2> <ul> <li>Remote server for hosting your site</li> <li>Create limited access git user (recommended)</li> <li>Create public/private SSH key pairs for authentication</li> <li>Add public key to authorized SSH keys</li> <li>Add private key to repository</li> <li>Setup Travis</li> <li>Setup travis.yml</li> </ul> <h2 id="generate-ssh-key-pairs"><a class="anchor-link" aria-hidden="true" href="#generate-ssh-key-pairs"></a>Generate SSH key pairs</h2> <p>Since I don&apos;t exactly feel comfortable giving Travis or Github my personal credentials to my own server, I&apos;m using SSH authentication in order to grant access to push. In addition, I&apos;ve created a <a href="">limited access git user</a> that only has access to my git and web directories -- nothing else.</p> <p>I&apos;m not going to go into great detail on how to create your SSH key pairs, since Github has <a href="">already done that for us</a>. You will need to login as your git user on your remote server, and generate a key pair following the above steps.</p> <p>Once you&apos;ve followed those steps, you should have two files <code>~/.ssh/id_rsa</code>, your private key and <code>~/.ssh/</code>, your public key. In order for the SSH authentication to work properly you will need to copy your public key into an authorized keys file.</p> <pre><code class="lang-bash">cat ~/.ssh/ &gt;&gt; ~/.ssh/authorized_keys </code></pre> <h2 id="add-private-key-to-repository"><a class="anchor-link" aria-hidden="true" href="#add-private-key-to-repository"></a>Add Private Key to Repository</h2> <p>Now that you&apos;ve created a SSH key pair, you will need to copy your private key so that Travis can use it to authenticate to your remote server. Since we don&apos;t want to be putting our <a href="">private key unencrypted</a> into Github, we&apos;ll be using Travis to encrypt the key before we push it out for everyone to see. You will need to install either the Travis ruby gem, or travis-encrypt from npm if you haven&apos;t already done so.</p> <h3 id="ruby"><a class="anchor-link" aria-hidden="true" href="#ruby"></a>Ruby</h3> <pre><code class="lang-ruby">gem install travis </code></pre> <h3 id="npm"><a class="anchor-link" aria-hidden="true" href="#npm"></a>NPM</h3> <pre><code>npm <span class="keyword">install</span> travis-<span class="keyword">encrypt</span> </code></pre><p>I&apos;m personally using the official Travis ruby gem, but the rest of the arguments should be about the same for both. You can read more about <a href="">Travis encryption</a>, but I&apos;m going to give you the Cliff Notes&#x2122; version here.</p> <p>Assuming you&apos;re already in your project directory, it&apos;s as easy as...</p> <pre><code class="lang-bash">mv id_rsa deploy_key touch .travis.yml &amp;&amp; travis encrypt-file deploy_key --add </code></pre> <p>This initializes the <code>.travis.yml</code> file, encrypts your deploy key, and adds all the necessary information for Travis to be able to use that encrypted file.</p> <p>You&apos;ll need to commit your changes to Github, but before you do so remember to remove your private key <code>deploy_key</code> and store it somewhere safe!</p> <h2 id="setup-travis"><a class="anchor-link" aria-hidden="true" href="#setup-travis"></a>Setup Travis</h2> <p>From here, you&apos;ll want to to go to <a href=""></a>, authenticate with Github, and turn on Travis for the repository that you wish to start deploying.</p> <p>From here, you&apos;ll need to make a few additions to your <code>.travis.yml</code> file, and I&apos;ll include an example, but you can of course always view the <a href="">latest version</a> on Github.</p> <pre><code class="lang-yaml"><span class="attr">language:</span> <span class="string">node_js</span> <span class="attr">node_js:</span> <span class="string">&apos;0.10&apos;</span> <span class="attr">install:</span> <span class="string">echo</span> <span class="string">&quot;skip install&quot;</span> <span class="attr">branches:</span> <span class="attr"> only:</span> <span class="string">master</span> <span class="attr">after_success:</span> <span class="bullet">-</span> <span class="string">chmod</span> <span class="number">600</span> <span class="string">deploy-key</span> <span class="bullet">-</span> <span class="string">mv</span> <span class="string">deploy-key</span> <span class="string">~/.ssh/id_rsa</span> <span class="bullet">-</span> <span class="string">git</span> <span class="string">remote</span> <span class="string">add</span> <span class="string">deploy</span> <span class="attr">ssh://</span> <span class="bullet">-</span> <span class="string">git</span> <span class="string">push</span> <span class="string">deploy</span> <span class="attr">before_install:</span> <span class="bullet">-</span> <span class="string">echo</span> <span class="bullet">-e</span> <span class="string">&quot;Host\n\tStrictHostKeyChecking no\n&quot;</span> <span class="string">&gt;&gt;</span> <span class="string">~/.ssh/config</span> <span class="bullet">-</span> <span class="string">openssl</span> <span class="string">aes-256-cbc</span> <span class="bullet">-K</span> <span class="string">$encrypted_6a5cf90fd664_key</span> <span class="bullet">-iv</span> <span class="string">$encrypted_6a5cf90fd664_iv</span> <span class="bullet"> -</span><span class="string">in</span> <span class="string">deploy-key.enc</span> <span class="bullet">-out</span> <span class="string">deploy-key</span> <span class="bullet">-d</span> </code></pre> <p>You&apos;ll need to change things accordingly to your needs, but here&apos;s a couple of tips:</p> <pre><code class="lang-yaml"><span class="attr">install:</span> <span class="string">echo</span> <span class="string">&quot;skip install&quot;</span> </code></pre> <p>I&apos;m essentially skipping this step because I&apos;m only using Travis to deploy, but theoretically, you could use this to run tests before the deployment actually runs.</p> <pre><code class="lang-yaml"><span class="attr">after_success:</span> <span class="bullet">-</span> <span class="string">chmod</span> <span class="number">600</span> <span class="string">deploy-key</span> <span class="bullet">-</span> <span class="string">mv</span> <span class="string">deploy-key</span> <span class="string">~/.ssh/id_rsa</span> <span class="bullet">-</span> <span class="string">git</span> <span class="string">remote</span> <span class="string">add</span> <span class="string">deploy</span> <span class="attr">ssh://</span> <span class="bullet">-</span> <span class="string">git</span> <span class="string">push</span> <span class="string">deploy</span> </code></pre> <p>Here&apos;s where the bulk of the work actually happen. Your private key is copied to the appropriate directory, and the remote origin is created and pushed to.</p> <pre><code>before_install: -<span class="ruby"> echo -e <span class="string">&quot;Host\n\tStrictHostKeyChecking no\n&quot;</span> <span class="meta">&gt;&gt; </span>~<span class="regexp">/.ssh/config</span></span> </code></pre><p>You will also need to change this to your domain as well, otherwise Travis may not be able to authenticate the domain and will sit there until the job times out.</p> <p>With this, any time I push to Github Travis is able to deploy those changes and immediately push them out to this blog. You can always view <a href="">everything on Github</a>.</p> </body></html>Remote Deployments with Githttps://scurker.com2015-01-25T00:00:00+00:00<html><head></head><body><p>I&apos;ve been deploying using git for my static and node sites for several months and wanted to offer some tips on how you can do the same. This is very similar to <a href="">heroku&apos;s deployment model</a> but using your own server in place of theirs.</p> <h3 id="getting-started"><a class="anchor-link" aria-hidden="true" href="#getting-started"></a>Getting Started</h3> <ul> <li>Remote server for hosting your site</li> <li>SSH access on remote server</li> <li>Git installed locally and remotely</li> <li>(optional) npm installed remotely</li> <li>(optional) grunt installed remotely</li> </ul> <p>For the remote server, you&apos;ll need two different directories to store your files. One is where your site will be hosted, the other will be used for the git repository. I&apos;m using <code>/var/www</code> and <code>/var/git</code> respectively, but you can choose differently based on your setup.</p> <h3 id="create-remote-repository"><a class="anchor-link" aria-hidden="true" href="#create-remote-repository"></a>Create remote repository</h3> <p>For the remote server, you&apos;ll need to start with a bare git repository. This is where you will push your content to from your local machine.</p> <pre><code class="lang-bash"><span class="built_in">cd</span> /var/git mkdir site.git &amp;&amp; <span class="built_in">cd</span> site.git git init --bare </code></pre> <h3 id="remote-dependencies"><a class="anchor-link" aria-hidden="true" href="#remote-dependencies"></a>Remote dependencies</h3> <p>Whatever you&apos;re using to build locally, you&apos;ll also need to be sure those dependencies are installed on your remote server. I&apos;m using <a href="">npm</a> and <a href="">grunt</a> to build everything - but this could be ruby, jekyll or anything used to compile your site.</p> <p>Since I&apos;m using grunt, we&apos;ll need to be sure that grunt-cli is installed globally.</p> <pre><code class="lang-bash">npm install -g grunt-cli </code></pre> <h3 id="create-post-receive-hook"><a class="anchor-link" aria-hidden="true" href="#create-post-receive-hook"></a>Create post receive hook</h3> <p>We&apos;ll be using a <a href="">post receive hook</a> to run tasks after commits are received, such as building the site. Since your git directory probably isn&apos;t where you&apos;re serving up your files, you can use <code>--work-tree</code> to set the working directory for your committed files.</p> <h4 id="post-receive-hook"><a class="anchor-link" aria-hidden="true" href="#post-receive-hook"></a>post-receive hook</h4> <pre><code class="lang-bash"><span class="meta">#!/bin/sh </span> <span class="comment"># Use a build path as a temp staging directory before copying over</span> <span class="comment"># to the &quot;live&quot; web directory</span> BUILD_PATH=$(<span class="built_in">cd</span> <span class="string">&quot;<span class="variable">$(dirname &quot;$0&quot;)</span>/..&quot;</span>; <span class="built_in">pwd</span>)/build WEB_PATH=/var/www/ <span class="comment"># Checkout latest version of files and cleanup untracked files</span> git --work-tree=<span class="variable">$BUILD_PATH</span> checkout -f git --work-tree=<span class="variable">$BUILD_PATH</span> clean -fd <span class="built_in">cd</span> <span class="variable">$BUILD_PATH</span>; npm install --production <span class="comment"># Use grunt to run a build task, but this could be anything you</span> <span class="comment"># want to use to generate your static site and/or run your node project</span> grunt build <span class="comment"># Clean web directory and copy static files to web directory</span> (<span class="built_in">cd</span> <span class="variable">$WEB_PATH</span>;rm -rf *) (cp -r <span class="variable">$BUILD_PATH</span>/build/. <span class="variable">$WEB_PATH</span>) </code></pre> <p>Be sure you make the post-receive hook executable.</p> <pre><code class="lang-bash">chmod +x hooks/post-receive </code></pre> <h3 id="set-up-push-to-deploy"><a class="anchor-link" aria-hidden="true" href="#set-up-push-to-deploy"></a>Set up Push to Deploy</h3> <p>Now that everything is configured remotely, you&apos;ll need to set up your local git to push to your remote server.</p> <pre><code class="lang-bash">git remote add deploy ssh:// </code></pre> <p>Now, you can push files to your remote server with one simple command:</p> <pre><code class="lang-bash">... git add . git commit -m <span class="string">&quot;Updating files&quot;</span> git push deploy </code></pre> <p>If everything worked successfully, you should be able to view your site and see updated changes.</p> <h4 id="add-ssh-key"><a class="anchor-link" aria-hidden="true" href="#add-ssh-key"></a>Add SSH key</h4> <p>Don&apos;t like typing your username and password every time you deploy? You can use a public SSH key to authenticate every time you do your push to deploy. If you haven&apos;t already generated your SSH keys, you can <a href="">follow this guide through step 2</a>.</p> <p>From there, you can simply copy your public key to your server.</p> <pre><code class="lang-bash">cat ~/.ssh/ | ssh <span class="string">&quot;cat &gt;&gt; ~/.ssh/authorized_keys&quot;</span> </code></pre> <p>What if you could automate your deployments? You can continue on reading on how you can enhance the push to deploy by making your deployments <a href="/automated-deploys-with-travis">completely automated with Travis CI</a>.</p> </body></html>Bring on a new scurker.comhttps://scurker.com2014-12-14T00:00:00+00:00<html><head></head><body><p>Welcome to the redesign and relaunch of! It&apos;s been far too long in my professional career that I have neglected this site, and felt that a new fresh coat of paint was long overdue.</p> <p>It&apos;s also been three years since I have contributed anything back to the community, and part of the goal for this relaunch is to better share what I know and have learned.</p> <h3 id="so-long-wordpress-"><a class="anchor-link" aria-hidden="true" href="#so-long-wordpress-"></a>So Long Wordpress!</h3> <p>Wordpress was a good start, but has finally outlived its usefulness and I&apos;ve moved on to greener pastures. I wanted something much more lightweight and with more friendly editing. I had initially looked at <a href="">ghost</a> along with a few other blogging platforms, but eventually decided that I didn&apos;t want to be encumbered by unnecessary overhead of yet another blog platform.</p> <h3 id="hello-wintersmith"><a class="anchor-link" aria-hidden="true" href="#hello-wintersmith"></a>Hello Wintersmith</h3> <p>Bring on <a href="">wintersmith</a>, a nodejs static site generator. I don&apos;t hate myself, so I also am using <a href="">wintersmith handlebars</a> over the built in Jade template engine. For my sanity and easier editing I can write every post or page in markdown - which wintersmith will automatically convert.</p> <h3 id="dependencies"><a class="anchor-link" aria-hidden="true" href="#dependencies"></a>Dependencies</h3> <ul> <li><a href="">wintersmith</a></li> <li><a href="">wintersmith handlebars</a></li> <li><a href="">grunt</a></li> <li><a href="">noto sans font</a></li> </ul> <p>There&apos;s some slightly modified plugins to wintersmith to allow for article to article pagination and a more sensible permalink structure.</p> <h3 id="no-more-jquery"><a class="anchor-link" aria-hidden="true" href="#no-more-jquery"></a>No more jQuery</h3> <p>I&apos;m a big fan of jQuery, but I have been <a href="">slowly moving away from having jQuery</a> as a dependency unless absolutely necessary. So you won&apos;t see very much jQuery used here.</p> <h3 id="open-sourced"><a class="anchor-link" aria-hidden="true" href="#open-sourced"></a>Open Sourced</h3> <p>I&apos;ve learned a lot through open source projects, and have spoken many times about the importance of open source. However, my own blog I kept private and didn&apos;t share what I knew. I figured it&apos;s time to start putting money where my mouth is and release the source for this site. You can check out everything on <a href="">github</a>. If you come across any issues, be sure to <a href="">let me know</a>.</p> </body></html>Go Mobile at TechMixer Universityhttps://scurker.com2011-09-25T00:00:00+00:00<html><head></head><body><p>I will be presenting a session on mobile web development this coming Tuesday, on September 28th. Slides will be posted shortly after the session is finished.</p> <ul> <li>Learn about recent trends regarding the mobile web</li> <li>&quot;Rethink&quot; developing for mobile</li> <li>Dive into mobile touch events and more!</li> </ul> <p>Couldn&apos;t make the session? View the slides online at <a href=""></a>.</p> <h3 id="techmixer-university"><a class="anchor-link" aria-hidden="true" href="#techmixer-university"></a>TechMixer University</h3> <p>TechMixer University is an annual one-day conference that offers a full day of free technology training. This Birmingham, Alabama event is attended by the area&#x2019;s brightest and enriched technical professionals, including developers, database professionals, project managers, network professionals, IT directors/managers and C-level executives.</p> <p><a href=""></a></p> </body></html>Amazon Trade-in Value Trackerhttps://scurker.com2011-04-13T00:00:00+00:00<html><head></head><body><p>This was a project that actually begin back in the summer of &apos;09. At the time Amazon had introduced a trade-in system with some pretty tempting promotions. However, there were limitations in that you could only see the most recent trade-in value with no ability for a history or a way to detect changes. Thus, the ativ tracker was born.</p> <p>Over a year later and with nearly 700,000 values tracked, the tracker is still chugging along but needed a new coat of paint. It&apos;s been updated with a new theme, some background improvements, better mobile optimizations, and charting utilizing <a href="">Rapha&#xEB;lJS</a>.</p> <p>A lot of sweat and hard work was put into this project to make it easy to track trade-in values. So if you have some old games sitting in your closet, why not consider <a href="">checking out the tracker</a> and turning your games into Amazon credit?</p> </body></html>Scurker Levels Uphttps://scurker.com2010-12-14T00:00:00+00:00<html><head></head><body><p>Welcome to the new and improved! I&apos;d never felt comfortable with my previous design and never really felt inspired by it. There had been some things that I had felt had been missing, and the site lacked a lot of flexibility I was looking for. Shortly after my previous design had been launched, I begin work on this iteration giving time for things to settle in. What has changed?</p> <h3 id="standards-are-dead-"><a class="anchor-link" aria-hidden="true" href="#standards-are-dead-"></a>Standards Are Dead?</h3> <p>Well technically, no. Previously I have been using XHTML 1.0 strict, but have now switched to an HTML 5 doctype, which is simple as <code>&lt;!DOCTYPE html&gt;</code>. The majority of the features I plan on using are quite usable across most major browsers, so I see little reason not to make the switch.</p> <h3 id="portfolio"><a class="anchor-link" aria-hidden="true" href="#portfolio"></a>Portfolio</h3> <p>Thanks to features added with Wordpress 3.0, this has given me the ability to update new additions to the portfolio that much easier!</p> <h3 id="no-more-boring-fonts-"><a class="anchor-link" aria-hidden="true" href="#no-more-boring-fonts-"></a>No More Boring Fonts!</h3> <p>Goodbye Trebuchet MS, hello @font-face! Web fonts have wide support in a majority of browsers, so why not take advantage of it? The <a href="">Google Font API</a> is a great resource for doing so.</p> <p>This is only a portion of the site as the rest should come around the corner of the holidays. Please feel free to leave any comments or suggestions below.</p> </body></html>Particle Generator using HTML5's Canvashttps://scurker.com2010-06-04T00:00:00+00:00<html><head></head><body><p>Particle effects are pretty awesome. Particles by themselves are fairly simple, but by generating multitudes of particles with set variables you can create a range of effects such as fire, smoke, or water. A particle generator or emitter allows you to adjust the variables giving you control over the types of effects you can generate.</p> <p>I&apos;ve been working on another project that needed a particle generator, thus this demonstration was born.</p> <p>There are several presets I&apos;ve included, but you can easily generate new types of effects by playing around with the available variables on the presets.</p> <p>The demo does not give you access to everything so in order to create more fine tuned options, here&apos;s all the currently available variables:</p> <pre><code class="lang-javascript">{ <span class="attr">shape</span>: <span class="string">&apos;circle&apos;</span>, <span class="comment">// square or circle</span> velocity: <span class="keyword">new</span> Vector({<span class="attr">y</span>: <span class="number">-1</span>}), <span class="comment">// movement vector; only y is used</span> xVariance: <span class="number">0</span>, <span class="comment">// +/- start x position (random)</span> yVariance: <span class="number">0</span>, <span class="comment">// +/- start y position (random)</span> spawnSpeed: <span class="number">25</span>, <span class="comment">// # particles spawned per cycle</span> generations: <span class="number">100000</span>, <span class="comment">// # of cycles to run for</span> maxParticles: <span class="number">500</span>, <span class="comment">// max # of particles allowed on screen</span> size: <span class="number">20</span>, <span class="comment">// size of particles</span> sizeVariance: <span class="number">5</span>, <span class="comment">// +/- size of particles (random)</span> life: <span class="number">30</span>, <span class="comment">// # of cycles a particle can live</span> lifeVariance: <span class="number">10</span>, <span class="comment">// +/- lifetime of particle (random)</span> direction: <span class="number">0</span>, <span class="comment">// initial start direction</span> directionVariance: <span class="number">15</span>, <span class="comment">// +/- direction (random)</span> color: <span class="string">&apos;#fff&apos;</span>, <span class="comment">// can be hex code or rgb</span> opacity: <span class="number">1</span>, <span class="comment">// particle opacity</span> onDraw: <span class="function"><span class="keyword">function</span>(<span class="params">p</span>) </span>{ <span class="comment">// onDraw passes in the current particle and is called before each</span> <span class="comment">// particle is displayed on the screen. This function is used in</span> <span class="comment">// several of the presets to adjust the color or opacity given</span> <span class="comment">// the particle&apos;s current age and lifespan.</span> } } </code></pre> <p>If you are using Firefox and Firebug, you can create your own objects and update the particle generator by using <code>particles.update(myObject);</code> via the command line.</p> <p>As usual, HTML5 and Canvas is not currently supported by IE7/IE8, so you&apos;ll need to use another browser in order for this to work. The demo has been tested in Firefox, Safari and Chrome, but I highly recommend using Chrome for the demo as it seems to run the most efficient.</p> <p><a href="/projects/particles">On to the demo!</a> Or alternatively, view the source <a href="/projects/particles/js/particle.js">here</a>.</p> </body></html>Javascript Clock using HTML5 and Canvashttps://scurker.com2010-04-20T00:00:00+00:00<html><head><script src="//"></script> <script type="text/javascript" src="/projects/jclock/jclock.js"></script> <script type="text/javascript"> $(window).ready(function() { new jClock('/projects/jclock/clock.png', $('canvas').get(0)); }); </script> <style type="text/css"> #jclock { padding-top: 15px; padding-right: 15px; float: left; } </style> </head><body><p>I&apos;ve been finding myself becoming more interested in what HTML5 can do. As I see it HTML5 stands to be a potential replacement for flash, in addition to the features and interactivity that are made available by various javascript frameworks out there.</p> <p>A good starting point would be to start off with something simple, i.e. a clock. Here&apos;s a sample project I threw together to help make myself more familiar with HTML5&apos;s canvas.</p> <div id="jclock"> <canvas height="125" width="125"><img src="/projects/jclock/clock.png" alt="HTML5 isn&apos;t supported!" title="HTML5 isn&apos;t supported!"></canvas> </div> <p>The clock you see on the left is written completely in javascript and takes advantage of <a href="">HTML5 and the canvas element</a> -- no flash necessary.</p> <p>If you see a blank clock face with no hands, that means that your browser does not support HTML5. You will need to be using the latest version of <a href="">Chrome</a>, <a href="">Firefox</a>, <a href="">Opera</a> or <a href="">Safari</a> in order for the clock to work. IE does not currently natively support the canvas element.</p> <p>There are <a href="">several</a> <a href="">good</a> <a href="">canvas</a> <a href="">tutorials</a> out there so please check those if you want a more in-depth introduction to HTML5&apos;s canvas element.</p> <p>In order to use this clock, you&apos;ll need to setup your canvas element:</p> <pre><code class="lang-html"><span class="tag">&lt;<span class="name">canvas</span> <span class="attr">id</span>=<span class="string">&quot;jclock&quot;</span> <span class="attr">height</span>=<span class="string">&quot;125&quot;</span> <span class="attr">width</span>=<span class="string">&quot;125&quot;</span>&gt;</span> Content or message to display if the browser does not support Canvas/HTML5. <span class="tag">&lt;/<span class="name">canvas</span>&gt;</span> </code></pre> <p>Initializing the clock:</p> <pre><code class="lang-javascript">$(<span class="built_in">window</span>).load(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="keyword">new</span> jClock(<span class="string">&apos;my-clock-face-image.png&apos;</span>, $(<span class="string">&apos;#jclock&apos;</span>).get(<span class="number">0</span>)); }); </code></pre> <p>You can also pass in additional options to change items such as the hand colors, or image size. Here&apos;s the defaults as defined in the plugin:</p> <pre><code class="lang-javascript"><span class="comment">// override default options:</span> <span class="comment">// i.e. new jClock(&apos;image.png&apos;, $(&apos;#canvas&apos;).get(0), {shadow: false});</span> jClock.defaults = { <span class="attr">height</span>: <span class="number">125</span>, <span class="comment">// default height</span> width: <span class="number">125</span>, <span class="comment">// default width</span> secondHand: <span class="literal">true</span>, <span class="comment">// show the second hand</span> shadow: <span class="literal">true</span>, <span class="comment">// display shadows across all hands</span> second: { <span class="comment">// second hand style options</span> color: <span class="string">&apos;#f00&apos;</span>, <span class="attr">width</span>: <span class="number">2</span>, <span class="attr">start</span>: <span class="number">-10</span>, <span class="attr">end</span>: <span class="number">35</span>, <span class="attr">alpha</span>: <span class="number">1</span> }, <span class="attr">minute</span>: { <span class="comment">// minute hand style options</span> color: <span class="string">&apos;#fff&apos;</span>, <span class="attr">width</span>: <span class="number">3</span>, <span class="attr">start</span>: <span class="number">-7</span>, <span class="attr">end</span>: <span class="number">30</span>, <span class="attr">alpha</span>: <span class="number">1</span> }, <span class="attr">hour</span>: { <span class="comment">// hour hand style options</span> color: <span class="string">&apos;#fff&apos;</span>, <span class="attr">width</span>: <span class="number">4</span>, <span class="attr">start</span>: <span class="number">-7</span>, <span class="attr">end</span>: <span class="number">20</span>, <span class="attr">alpha</span>: <span class="number">1</span> } }; </code></pre> <p>Feel free to download the source code and play around with it, or ask any questions you may have in the comments below.</p> <p><a href="/projects/jclock/jclock.js">Download jclock.js (2.4k)</a></p> </body></html>Migration from Drupal 6.x to Wordpress 2.9xhttps://scurker.com2010-02-26T00:00:00+00:00<html><head></head><body><p>I recently found myself wanting to move my <a href="">personal blog</a> from <a href="">Drupal 6.x</a> to <a href="Wordpress">Wordpress</a> for various reasons. I primarily followed <a href="">this tutorial</a>, but wanted to outline some additional information in the transfer.</p> <h3 id="database-conversion-table"><a class="anchor-link" aria-hidden="true" href="#database-conversion-table"></a>Database Conversion Table</h3> <table> <thead> <tr> <th>Drupal 6.x Table(s)</th> <th>Wordpress 2.9x Equivalent</th> </tr> </thead> <tbody> <tr> <td>term_data, term_hierarchy</td> <td>wp_terms</td> </tr> <tr> <td>node, node_revisions</td> <td>wp_posts</td> </tr> <tr> <td>term_node</td> <td>wp_term_relationships</td> </tr> <tr> <td>comments</td> <td>wp_comments</td> </tr> </tbody> </table> <h3 id="truncate-wordpress-tables"><a class="anchor-link" aria-hidden="true" href="#truncate-wordpress-tables"></a>Truncate Wordpress Tables</h3> <p>First, I needed to remove any data that is currently in certain wordpress tables so I could work with a fresh slate.</p> <p><em>Note:</em> By default when you install wordpress all tables are prefixed with <code>wp_</code> unless you changed it to something else. The below queries will need to be modified if you used anything else other than <code>wp_</code>.</p> <pre><code class="lang-sql"><span class="keyword">TRUNCATE</span> <span class="keyword">TABLE</span> wp_comments; <span class="keyword">TRUNCATE</span> <span class="keyword">TABLE</span> wp_postmeta; <span class="keyword">TRUNCATE</span> <span class="keyword">TABLE</span> wp_posts; <span class="keyword">TRUNCATE</span> <span class="keyword">TABLE</span> wp_term_relationships; <span class="keyword">TRUNCATE</span> <span class="keyword">TABLE</span> wp_term_taxonomy; <span class="keyword">TRUNCATE</span> <span class="keyword">TABLE</span> wp_terms; </code></pre> <h3 id="import-taxonomy-terms"><a class="anchor-link" aria-hidden="true" href="#import-taxonomy-terms"></a>Import Taxonomy Terms</h3> <p>The next sets of queries imports taxonomy terms.</p> <p><em>Note:</em> Table names pre-pended with <code>drupal.</code> needs to be the actual name of your drupal database. You will need to change this to whatever you have your drupal database named.</p> <pre><code class="lang-sql"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> wp_terms (term_id, <span class="keyword">name</span>, slug, term_group) <span class="keyword">SELECT</span> d.tid,, <span class="keyword">REPLACE</span>(<span class="keyword">LOWER</span>(, <span class="string">&apos; &apos;</span>, <span class="string">&apos;-&apos;</span>), <span class="number">0</span> <span class="keyword">FROM</span> drupal.term_data d <span class="keyword">INNER</span> <span class="keyword">JOIN</span> drupal.term_hierarchy h <span class="keyword">USING</span>(tid); </code></pre> <p>By default, Wordpress has several taxonomy types available; <code>categories</code>, <code>post_tag</code>, and <code>link_category</code>. In my Drupal instance I used taxonomy primarily as tags, but you may have a different need. You may need to modify the 3rd line in the below query depending on how you want taxonomies imported:</p> <ul> <li><em>Categories</em>: <code>category</code></li> <li><em>Link Categories</em>: <code>link_category</code></li> <li><em>Post Tags</em>: <code>post_tag</code></li> </ul> <pre><code class="lang-sql"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> wp_term_taxonomy (term_taxonomy_id, term_id, taxonomy, description, <span class="keyword">parent</span>) <span class="keyword">SELECT</span> d.tid, d.tid, <span class="string">&apos;post_tag&apos;</span>, d.description, h.parent <span class="keyword">FROM</span> drupal.term_data d <span class="keyword">INNER</span> <span class="keyword">JOIN</span> drupal.term_hierarchy h <span class="keyword">USING</span>(tid); </code></pre> <h3 id="import-post-content"><a class="anchor-link" aria-hidden="true" href="#import-post-content"></a>Import Post Content</h3> <p>Drupal allows for custom post types, while as of Wordpress 2.9x, custom post types are only available via plugins. You can use the below query unmodified and it will convert all stories to posts, and everything else will transfer over as is. If you need to convert additional post types, you can add additional case statements.</p> <p>Example: <code>WHEN &apos;book&apos; THEN &apos;post&apos;</code></p> <p>I also adjusted the query so that &apos;post_date_gmt&apos; would be populated correctly based on my GMT offset of -6:00 (Central Time). If you are in a different timezone you will need to adjust <code>FROM_UNIXTIME(created+21600)</code> to subtract or add correctly based on your location.</p> <pre><code class="lang-sql"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> wp_posts (<span class="keyword">id</span>, post_date, post_date_gmt, post_content, post_title, post_excerpt, post_name, post_type, post_modified) <span class="keyword">SELECT</span> <span class="keyword">DISTINCT</span> n.nid, FROM_UNIXTIME(created), FROM_UNIXTIME(created+<span class="number">21600</span>), <span class="keyword">body</span>, n.title, teaser, <span class="keyword">LOWER</span>(n.title), (<span class="keyword">CASE</span> n.type <span class="keyword">WHEN</span> <span class="string">&apos;story&apos;</span> <span class="keyword">THEN</span> <span class="string">&apos;post&apos;</span> <span class="keyword">ELSE</span> n.type <span class="keyword">END</span>) <span class="keyword">as</span> <span class="keyword">type</span>, FROM_UNIXTIME(<span class="keyword">changed</span>) <span class="keyword">FROM</span> drupal.node n, drupal.node_revisions r <span class="keyword">WHERE</span> n.vid = r.vid; </code></pre> <h3 id="import-post-and-taxonomy-relationships"><a class="anchor-link" aria-hidden="true" href="#import-post-and-taxonomy-relationships"></a>Import Post and Taxonomy Relationships</h3> <pre><code class="lang-sql"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> wp_term_relationships (object_id, term_taxonomy_id) <span class="keyword">SELECT</span> nid, tid <span class="keyword">FROM</span> drupal.term_node; </code></pre> <h3 id="category-count-updating"><a class="anchor-link" aria-hidden="true" href="#category-count-updating"></a>Category Count Updating</h3> <pre><code class="lang-sql"><span class="keyword">UPDATE</span> wp_term_taxonomy tt <span class="keyword">SET</span> <span class="keyword">count</span> = ( <span class="keyword">SELECT</span> <span class="keyword">COUNT</span>(tr.object_id) <span class="keyword">FROM</span> wp_term_relationships tr <span class="keyword">WHERE</span> tr.term_taxonomy_id = tt.term_taxonomy_id ); </code></pre> <h3 id="import-comments"><a class="anchor-link" aria-hidden="true" href="#import-comments"></a>Import Comments</h3> <pre><code class="lang-sql"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> wp_comments (comment_post_ID, comment_date, comment_content, comment_parent, comment_author, comment_author_email, comment_author_url, comment_approved) <span class="keyword">SELECT</span> nid, FROM_UNIXTIME(<span class="keyword">timestamp</span>), <span class="keyword">comment</span>, <span class="keyword">thread</span>, <span class="keyword">name</span>, mail, homepage, <span class="keyword">status</span> <span class="keyword">FROM</span> drupal.comments; </code></pre> <h3 id="update-comment-count"><a class="anchor-link" aria-hidden="true" href="#update-comment-count"></a>Update Comment Count</h3> <pre><code class="lang-sql"><span class="keyword">UPDATE</span> wp_posts <span class="keyword">SET</span> comment_count = (<span class="keyword">SELECT</span> <span class="keyword">COUNT</span>(comment_post_id) <span class="keyword">FROM</span> wp_comments <span class="keyword">WHERE</span> = wp_comments.comment_post_id); </code></pre> <h3 id="update-post-slugs"><a class="anchor-link" aria-hidden="true" href="#update-post-slugs"></a>Update Post Slugs</h3> <p>Drupal&apos;s URL aliases is equivalent to Wordpress&apos; permalinks. Drupal has a much more aggressive title sanitation than Wordpress. I wanted the ability to keep my titles the same for SEO reasons when migrating over to Wordpress.</p> <p>In order to keep my old titles, I need to hook into Wordpress&apos; <a href="">title sanitation</a> with similar rules to Drupal. The below code will need to be placed somewhere in the <code>functions.php</code> file of your current theme.</p> <pre><code class="lang-php">add_filter(<span class="string">&apos;sanitize_title&apos;</span>, <span class="string">&apos;my_sanitize_title&apos;</span>); <span class="function"><span class="keyword">function</span> <span class="title">my_sanitize_title</span><span class="params">($title)</span> </span>{ $title = preg_replace(<span class="string">&apos;/\b(a|an|as|at|before|but|by|for|from|is|in|into|like|of|off|on|onto|per|since|than|the|this|that|to|up|via|with)\b/i&apos;</span>, <span class="string">&apos;&apos;</span>, $title); $title = preg_replace(<span class="string">&apos;/-+/&apos;</span>, <span class="string">&apos;-&apos;</span>, $title); $title = trim($title, <span class="string">&apos;-&apos;</span>); <span class="keyword">return</span> $title; } </code></pre> <p>You will need to save the below code to a file i.e. &quot;fix-slugs.php&quot; in your main Wordpress directory and run it through your browser.</p> <pre><code class="lang-php"><span class="meta">&lt;?php</span> <span class="keyword">require_once</span>(<span class="string">&apos;wp-load.php&apos;</span>); $posts = $wpdb-&gt;get_results( <span class="string">&quot;SELECT ID, post_title, post_name FROM $wpdb-&gt;posts&quot;</span> ); $count = <span class="number">0</span>; $ignored = <span class="number">0</span>; $errors = <span class="number">0</span>; <span class="keyword">foreach</span>($posts <span class="keyword">as</span> $post) { <span class="keyword">if</span>(strcmp($slug = sanitize_title($post-&gt;post_title), $post-&gt;post_name) !== <span class="number">0</span>) { $wpdb-&gt;show_errors(); <span class="keyword">if</span>(($result = $wpdb-&gt;query(<span class="string">&quot;UPDATE $wpdb-&gt;posts SET post_name=&apos;$slug&apos; WHERE ID=$post-&gt;ID&quot;</span>)) === <span class="keyword">false</span>) { $errors++; } <span class="keyword">elseif</span>($result === <span class="number">0</span>) { $ignore++; } <span class="keyword">else</span> { $count++; } } <span class="keyword">else</span> { $ignored++; } } <span class="keyword">echo</span> <span class="string">&quot;*$count post slug(s) sanitized.*&lt;br /&gt;&quot;</span>; <span class="keyword">echo</span> <span class="string">&quot;$ignored post(s) ignored.&lt;br /&gt;&quot;</span>; <span class="keyword">echo</span> <span class="string">&quot;$errors error(s).&lt;br /&gt;&quot;</span>; </code></pre> <p>If you were following along with <a href="">this tutorial</a>, I&apos;ve made a few changes based on my Drupal setup using <a href="">Wordpress database description</a> as a reference when I ran into issues. There may be some additional steps to be completed if you uploaded images through Drupal&apos;s interface, but the above queries were able to successfully migrate my data from Drupal to Wordpress.</p> </body></html>A new beginninghttps://scurker.com2010-01-19T00:00:00+00:00<html><head></head><body><p>You&apos;ve undoubtedly reached this site through either word of mouth, or via my <a href="">personal blog</a>, but I&apos;d like to formally welcome you to the new! I&apos;ve been hard at work over the past week in order to get everything up and running and am happy to finally be at this point.</p> <p>One of my big reasons for rolling over to a new design was the limitations my old site was giving me. I wanted to have a new fresher design in addition to having more flexibility with the content on the site. Now with the addition of <a href="">wordpress</a>, I can easily outline new projects or post about some dramatic revolution in web design. In addition the new site will help me give a better showcase for my skills and abilities for any future clients and/or employers.</p> <p>You are not seeing the final version of this roll-out, but features will slowly be added as I get time. Please feel free to post a comment if you notice any issues, or <a href="/about">contact me</a> if you have any opportunities you would like to discuss.</p> </body></html>