<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Posts - Scott Robinson · @ssxio</title>
  <subtitle>I&#39;m a software developer located in Staffordshire, United Kingdom specialising in PHP, Laravel and APIs. I love open source, data and sharing the things I learn.</subtitle>
  <link href="https://dor.ky/posts/feed" rel="self"/>
  <link href="https://dor.ky"/>
  <updated>2009-12-10T19:23:24-00:00</updated>
  <id>https://dor.ky</id>
  <author>
    <name>Scott Robinson</name>
    <email>scott@dor.ky</email>
  </author>
  
  
  <entry>
    <title>How to Detect Service Versions on Adobe Commerce Cloud</title>
    
    <link href="https://dor.ky/posts/2026/04/detect-service-versions-adobe-commerce-cloud/" rel="alternate" type="text/html"/>
    
    <updated>2026-04-10T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2026/04/detect-service-versions-adobe-commerce-cloud/</id>
    <content type="html">&lt;p&gt;Adobe Commerce Cloud manages your infrastructure services for you, but knowing exactly which versions of Valkey, MariaDB and RabbitMQ are running on your environments isn’t always obvious. The &lt;code&gt;.magento/services.yaml&lt;/code&gt; file defines what you’ve requested, but that doesn’t always reflect what’s actually deployed - especially after platform upgrades or environment redeployments.&lt;/p&gt;
&lt;p&gt;Here’s how to check the actual running versions by SSH’ing into your environment.&lt;/p&gt;
&lt;h2 id=&quot;valkey&quot;&gt;Valkey&lt;/h2&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ valkey-server -v&lt;br&gt;Valkey server &lt;span class=&quot;token assign-left variable&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8.0&lt;/span&gt;.1 &lt;span class=&quot;token assign-left variable&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;4fbab574:0 &lt;span class=&quot;token assign-left variable&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;jemalloc-5.3.0 &lt;span class=&quot;token assign-left variable&quot;&gt;bits&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;84a9272b225dd059&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your environment is still running Redis rather than Valkey, you can use &lt;code&gt;redis-server -v&lt;/code&gt; instead.&lt;/p&gt;
&lt;h2 id=&quot;mariadb&quot;&gt;MariaDB&lt;/h2&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ mariadb -V&lt;br&gt;mariadb  Ver &lt;span class=&quot;token number&quot;&gt;15.1&lt;/span&gt; Distrib &lt;span class=&quot;token number&quot;&gt;10.11&lt;/span&gt;.9-MariaDB, &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; debian-linux-gnu &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x86_64&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; using readline &lt;span class=&quot;token number&quot;&gt;5.2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the uppercase &lt;code&gt;-V&lt;/code&gt; flag here - lowercase &lt;code&gt;-v&lt;/code&gt; won’t give you what you need.&lt;/p&gt;
&lt;h2 id=&quot;rabbitmq&quot;&gt;RabbitMQ&lt;/h2&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ dpkg -s rabbitmq-server &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; Version&lt;br&gt;Version: &lt;span class=&quot;token number&quot;&gt;4.1&lt;/span&gt;.0-1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;RabbitMQ doesn’t have a straightforward version flag like the others, so querying the installed package via &lt;code&gt;dpkg&lt;/code&gt; is the simplest approach.&lt;/p&gt;
&lt;h2 id=&quot;why-this-matters&quot;&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;Knowing your actual service versions is useful when debugging compatibility issues, preparing for upgrades or verifying that a platform change has actually taken effect. It’s also handy when raising support tickets with Adobe - having the exact version numbers saves a fair amount of back and forth.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Blocking SessionReaper and PolyShell File Access with Fastly on Magento/Adobe Commerce</title>
    
    <link href="https://dor.ky/posts/2026/03/blocking-polyshell-sessionreaper-access-fastly-magento/" rel="alternate" type="text/html"/>
    
    <updated>2026-03-30T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2026/03/blocking-polyshell-sessionreaper-access-fastly-magento/</id>
    <content type="html">&lt;p&gt;If you’ve been keeping an eye on the Magento security space recently, you’ll have seen the research from Sansec around &lt;a href=&quot;https://sansec.io/research/sessionreaper-exploitation&quot;&gt;SessionReaper exploitation&lt;/a&gt; and the more recent &lt;a href=&quot;https://sansec.io/research/magento-polyshell&quot;&gt;PolyShell&lt;/a&gt; - both of which use the &lt;code&gt;media/custom_options/&lt;/code&gt; directory as a vector for uploading and executing malicious PHP files.&lt;/p&gt;
&lt;p&gt;The SessionReaper attack targets session data to extract customer and admin credentials, and the PolyShell technique builds on this by disguising executable PHP within files that appear to be valid image uploads.&lt;/p&gt;
&lt;h2 id=&quot;blocking-access-at-the-edge-with-fastly&quot;&gt;Blocking access at the edge with Fastly&lt;/h2&gt;
&lt;p&gt;If you’re running Adobe Commerce Cloud or any Magento instance fronted by Fastly, you can block access to these paths before requests ever reach your origin server. This is a fairly simple &lt;a href=&quot;https://experienceleague.adobe.com/en/docs/commerce-on-cloud/user-guide/cdn/custom-vcl-snippets/fastly-vcl-custom-snippets&quot;&gt;custom VCL snippet&lt;/a&gt; that returns a &lt;code&gt;403&lt;/code&gt; for any request targeting &lt;code&gt;media/custom_options/&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^/media/custom_options/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  error &lt;span class=&quot;token number&quot;&gt;403&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Forbidden&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add this as a custom VCL snippet in your Fastly configuration with the type set to &lt;code&gt;recv&lt;/code&gt; and priority &lt;code&gt;1&lt;/code&gt;. This will catch any direct access attempts to files within that directory - whether they’re SessionReaper scripts, PolyShell payloads or anything else that has no business being served publicly.&lt;/p&gt;
&lt;h2 id=&quot;edge-level-blocking-over-application-level-blocking&quot;&gt;Edge-level blocking over application-level blocking&lt;/h2&gt;
&lt;p&gt;Blocking at Fastly rather than at the application level means the request never reaches nginx, Varnish or PHP. This is important for two reasons - it reduces the attack surface significantly and it means even if an attacker has managed to upload a malicious file, they can’t execute it by requesting it directly through the public URL.&lt;/p&gt;
&lt;p&gt;You should still be auditing your &lt;code&gt;media/custom_options/&lt;/code&gt; directory for any suspicious files and ensuring your Magento instance is patched, but adding this edge-level block is a solid defensive layer that takes seconds to deploy.&lt;/p&gt;
&lt;h2 id=&quot;important-note&quot;&gt;Important Note&lt;/h2&gt;
&lt;p&gt;If your store actively uses custom options with file upload fields on products, you’ll need to be more careful with this approach. Blanket blocking the entire &lt;code&gt;media/custom_options/&lt;/code&gt; path could interfere with legitimate file uploads that customers need to access. In that case you may need to refine the VCL to target specific file extensions or patterns rather than the whole directory.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further reading&lt;/h2&gt;
&lt;p&gt;Sansec’s research on both of these attack vectors is well worth a read if you haven’t already:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://sansec.io/research/sessionreaper-exploitation&quot;&gt;SessionReaper Exploitation&lt;/a&gt; - the session hijacking attack targeting customer and admin credentials&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sansec.io/research/magento-polyshell&quot;&gt;Magento PolyShell&lt;/a&gt; - the PolyShell research that builds on the SessionReaper technique&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With a bit of luck this saves you from a headache down the line. If you’re not already monitoring your media directories for unexpected PHP files, now is a good time to start.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Fixing Magento&#39;s Telephone Validation to Allow Dots and Slashes</title>
    
    <link href="https://dor.ky/posts/2026/03/magento-telephone-validation-dots-slashes/" rel="alternate" type="text/html"/>
    
    <updated>2026-03-23T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2026/03/magento-telephone-validation-dots-slashes/</id>
    <content type="html">&lt;p&gt;Magento’s built-in telephone validation for customer accounts is fairly strict - it only allows digits, spaces, parentheses, plus signs and hyphens. That works for a lot of western formats but breaks for plenty of valid international phone numbers.&lt;/p&gt;
&lt;p&gt;French phone numbers are commonly written with dots as separators (e.g. &lt;code&gt;06.76.40.32.22&lt;/code&gt;), and Austrian numbers often use a forward slash (e.g. &lt;code&gt;+43680/2149568&lt;/code&gt;). Both of these formats are rejected by Magento’s &lt;code&gt;Telephone&lt;/code&gt; validator out of the box.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Telephone&lt;/code&gt; model validator in &lt;code&gt;vendor/magento/module-customer/Model/Validator/Telephone.php&lt;/code&gt; uses a regex pattern that doesn’t account for dots or slashes:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PATTERN_TELEPHONE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;/(?:[\d\s\+\-\()]{1,20})/u&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means any customer trying to save their phone number in a perfectly valid international format gets hit with “Invalid Phone Number” - not a great experience.&lt;/p&gt;
&lt;p&gt;The issue is tracked internally as ACP2E-4554 and was discussed in &lt;a href=&quot;https://github.com/magento/magento2/issues/40544&quot;&gt;magento/magento2#40544&lt;/a&gt; and &lt;a href=&quot;https://github.com/magento/magento2/pull/40545&quot;&gt;magento/magento2#40545&lt;/a&gt;. The &lt;a href=&quot;https://github.com/magento/magento2/commit/ca060df75cbb1350bbd1303cb8d0f0377d1d94f6&quot;&gt;fix was committed&lt;/a&gt; but if you’re on a version that doesn’t include it yet, here’s a patch.&lt;/p&gt;
&lt;p&gt;Here’s an m2-hotfixes patch that adds support for dots and forward slashes in telephone validation:&lt;/p&gt;
&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token coord&quot;&gt;--- a/vendor/magento/module-customer/Model/Validator/Telephone.php&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;+++ b/vendor/magento/module-customer/Model/Validator/Telephone.php&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;@@ -21,9 +21,11 @@&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt;      * \() :Matches open and close parentheses&lt;br&gt;      * \+: Matches the plus sign.&lt;br&gt;      * \-: Matches the hyphen.&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+     * \.: Matches the dot character (e.g. 06.76.40.32.22)&lt;br&gt;+     * \/: Matches the forward slash (e.g. +43680/2149568)&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;      * \d: Digits (0-9).&lt;br&gt;      */&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    private const PATTERN_TELEPHONE = &#39;/(?:[\d\s\+\-\()]{1,20})/u&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    private const PATTERN_TELEPHONE = &#39;/(?:[\d\s+().\/ -]{1,20})/u&#39;;&lt;br&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt;     /**&lt;br&gt;      * Validate telephone fields.&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token coord&quot;&gt;@@ -35,7 +37,7 @@&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt;     {&lt;br&gt;         if (!$this-&gt;isValidTelephone($customer-&gt;getTelephone())) {&lt;br&gt;             parent::_addMessages([[&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-                &#39;telephone&#39; =&gt; &quot;Invalid Phone Number. Please use 0-9, +, -, (, ) and space.&quot;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+                &#39;telephone&#39; =&gt; &quot;Invalid Phone Number. Please use 0-9, +, -, (, ), ., / and space.&quot;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;             ]]);&lt;br&gt;         }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save this as &lt;code&gt;m2-hotfixes/ac-13791__telephone-validation-dots-slashes.patch&lt;/code&gt; (or whatever naming convention you use for your hotfixes directory).&lt;/p&gt;
&lt;p&gt;The updated regex pattern &lt;code&gt;&#39;/(?:[\d\s+().\/ -]{1,20})/u&#39;&lt;/code&gt; adds &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;/&lt;/code&gt; to the allowed character set.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Creating URL Redirects When Updating Product URL Keys via the Magento API</title>
    
    <link href="https://dor.ky/posts/2026/03/magento-api-url-key-create-redirect/" rel="alternate" type="text/html"/>
    
    <updated>2026-03-12T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2026/03/magento-api-url-key-create-redirect/</id>
    <content type="html">&lt;p&gt;If you’ve ever updated a product’s URL key via the Magento 2 REST API and then wondered why the old URL is now returning a 404, you’ve probably missed the &lt;code&gt;url_key_create_redirect&lt;/code&gt; custom attribute.&lt;/p&gt;
&lt;p&gt;In the admin UI there’s a handy “Create Permanent Redirect for old URL” checkbox that appears when you change a product’s URL key. Behind the scenes, this sets &lt;code&gt;url_key_create_redirect&lt;/code&gt; on the product - and you can pass exactly the same attribute in your API requests to get the same behaviour.&lt;/p&gt;
&lt;h2 id=&quot;the-api-request&quot;&gt;The API request&lt;/h2&gt;
&lt;p&gt;When updating a product’s URL key, include &lt;code&gt;url_key_create_redirect&lt;/code&gt; alongside &lt;code&gt;url_key&lt;/code&gt; in your &lt;code&gt;custom_attributes&lt;/code&gt; array:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;PUT /rest/V1/products/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;sku&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;product&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;custom_attributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;attribute_code&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;url_key&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;new-product-url-key&quot;&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;attribute_code&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;url_key_create_redirect&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Setting the value to &lt;code&gt;1&lt;/code&gt; tells Magento to create a 301 redirect from the old URL to the new one. The redirect is written to the &lt;code&gt;url_rewrite&lt;/code&gt; table with &lt;code&gt;redirect_type&lt;/code&gt; set to &lt;code&gt;301&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you want to suppress redirect creation entirely - for example during a bulk initial import where no old URLs exist yet - set the value to &lt;code&gt;0&lt;/code&gt; or omit the attribute.&lt;/p&gt;
&lt;h2 id=&quot;why-this-matters-for-bulk-operations&quot;&gt;Why this matters for bulk operations&lt;/h2&gt;
&lt;p&gt;If you’re running a bulk URL key update across hundreds or thousands of products, you’ll want to be deliberate about this. Passing &lt;code&gt;url_key_create_redirect: 1&lt;/code&gt; on every product creates a redirect entry for each one, which can pile up in &lt;code&gt;url_rewrite&lt;/code&gt; over time - especially if products have had multiple URL key changes.&lt;/p&gt;
&lt;p&gt;It’s worth cleaning out stale redirects periodically, or being selective about which updates warrant a redirect versus which are clean-slate changes (new products, dev/staging refreshes, etc.).&lt;/p&gt;
&lt;h2 id=&quot;verifying-the-redirect-was-created&quot;&gt;Verifying the redirect was created&lt;/h2&gt;
&lt;p&gt;You can check the &lt;code&gt;url_rewrite&lt;/code&gt; table directly after the API call:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; url_rewrite&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; entity_type &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;product&#39;&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; redirect_type &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;301&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; target_path &lt;span class=&quot;token operator&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;%new-product-url-key%&#39;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; url_rewrite_id &lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;LIMIT&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or use the REST API to inspect the product’s URL rewrites:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;GET /rest/V1/url-rewrites/products/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;product_id&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With a bit of luck this saves you the debugging time of wondering why your URL key updates are silently dropping old links.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Fixing Broken Product Relationships in Adobe Commerce/Magento 2</title>
    
    <link href="https://dor.ky/posts/2026/02/fix-broken-product-relationships-magento-adobe-commerce/" rel="alternate" type="text/html"/>
    
    <updated>2026-02-17T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2026/02/fix-broken-product-relationships-magento-adobe-commerce/</id>
    <content type="html">&lt;p&gt;I recently ran into a fairly puzzling issue on an Adobe Commerce site where some products were behaving oddly on the frontend. After some digging, it turned out the &lt;code&gt;catalog_product_relation&lt;/code&gt; and &lt;code&gt;catalog_product_super_link&lt;/code&gt; tables had invalid entries - simple products were listed as parents with child relationships, which should never happen.&lt;/p&gt;
&lt;p&gt;In Magento/Adobe Commerce, only configurable, bundle and grouped products should have child relationships. When simple products end up with children in these tables, it’s usually the result of a botched import, a failed product type conversion or some other data corruption.&lt;/p&gt;
&lt;h2 id=&quot;finding-the-problem&quot;&gt;Finding the problem&lt;/h2&gt;
&lt;p&gt;First, identify any invalid entries in &lt;code&gt;catalog_product_relation&lt;/code&gt; where the parent is a simple product:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;&lt;br&gt;    cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;child_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entity_id &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; parent_entity_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sku &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; parent_sku&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type_id &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; parent_type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entity_id &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; child_entity_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sku &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; child_sku&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type_id &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; child_type&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt;&lt;br&gt;    catalog_product_relation cpr&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt;&lt;br&gt;    catalog_product_entity parent &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt;&lt;br&gt;    catalog_product_entity child &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;child_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt;&lt;br&gt;    parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;simple&#39;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt;&lt;br&gt;    parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entity_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entity_id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, check &lt;code&gt;catalog_product_super_link&lt;/code&gt; for non-configurable parents (this table should only contain configurable product relationships):&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;&lt;br&gt;    cpsl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;link_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    cpsl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;product_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    cpsl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entity_id &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; parent_entity_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sku &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; parent_sku&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type_id &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; parent_type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entity_id &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; child_entity_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sku &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; child_sku&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type_id &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; child_type&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt;&lt;br&gt;    catalog_product_super_link cpsl&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt;&lt;br&gt;    catalog_product_entity parent &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; cpsl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt;&lt;br&gt;    catalog_product_entity child &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; cpsl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;product_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt;&lt;br&gt;    parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type_id &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;configurable&#39;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt;&lt;br&gt;    parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entity_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entity_id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also get a quick count of how many invalid entries exist:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;catalog_product_relation&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; table_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;       &lt;span class=&quot;token function&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; invalid_count&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;       &lt;span class=&quot;token string&quot;&gt;&#39;Parents with type_id=simple&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; issue&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; catalog_product_relation cpr&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; catalog_product_entity parent &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;simple&#39;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;UNION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ALL&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;catalog_product_super_link&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; table_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;       &lt;span class=&quot;token function&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; invalid_count&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;       &lt;span class=&quot;token string&quot;&gt;&#39;Parents with type_id!=configurable&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; issue&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; catalog_product_super_link cpsl&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; catalog_product_entity parent &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; cpsl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type_id &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;configurable&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;checking-for-orphans&quot;&gt;Checking for orphans&lt;/h2&gt;
&lt;p&gt;While you’re at it, check for orphaned references where the parent or child product no longer exists:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Missing parents in catalog_product_relation&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;child_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Missing parent&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; issue&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; catalog_product_relation cpr&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;LEFT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; catalog_product_entity parent &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;-- Missing children in catalog_product_relation&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;child_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Missing child&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; issue&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; catalog_product_relation cpr&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;LEFT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; catalog_product_entity child &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;child_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;cleaning-up&quot;&gt;Cleaning up&lt;/h2&gt;
&lt;p&gt;Back up your database first. Then remove the invalid entries:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Remove invalid entries from catalog_product_relation&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; cpr&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; catalog_product_relation cpr&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; catalog_product_entity parent &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; cpr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;simple&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;-- Remove invalid entries from catalog_product_super_link&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; cpsl&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; catalog_product_super_link cpsl&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; catalog_product_entity parent &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; cpsl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parent_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;row_id&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type_id &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;configurable&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After cleanup, reindex and clear cache:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;bin/magento indexer:reindex&lt;br&gt;bin/magento cache:clean&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing to consider - if those simple products &lt;em&gt;should&lt;/em&gt; actually be configurable products, you’ll need to convert them rather than just deleting the relationships. The queries above assume the relationships themselves are the problem, not the product types.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Disable Chrome AI Mode in the Omnibox</title>
    
    <link href="https://dor.ky/posts/2026/02/disable-chrome-ai-mode-omnibox/" rel="alternate" type="text/html"/>
    
    <updated>2026-02-09T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2026/02/disable-chrome-ai-mode-omnibox/</id>
    <content type="html">&lt;p&gt;If you want to disable the AI mode button that appears in Chrome’s omnibox/address bar then you can do so via Chrome flags.&lt;/p&gt;
&lt;p&gt;Navigate to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chrome://flags/#ai-mode-omnibox-entry-point
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set the flag to &lt;strong&gt;Disabled&lt;/strong&gt; and relaunch Chrome.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Claude Code - How to Revert Back to Opus 4.5 from Opus 4.6</title>
    
    <link href="https://dor.ky/posts/2026/02/claude-code-how-to-revert-back-to-opus-4-5-from-opus-4-6/" rel="alternate" type="text/html"/>
    
    <updated>2026-02-02T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2026/02/claude-code-how-to-revert-back-to-opus-4-5-from-opus-4-6/</id>
    <content type="html">&lt;p&gt;If you want to go back to Opus 4.5, start hashtag#claude with:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;claude --model claude-opus-4-5-20251101&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also edit your config file to set this as the default if you want to use it by default rather than 4.6.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Signing Git Commits with SSH</title>
    
    <link href="https://dor.ky/posts/2026/01/signing-git-commits-with-ssh/" rel="alternate" type="text/html"/>
    
    <updated>2026-01-26T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2026/01/signing-git-commits-with-ssh/</id>
    <content type="html">&lt;p&gt;I recently ran into a “No signature” error when trying to get my git commits verified and it sent me down a bit of a rabbit hole. If you’ve ever tried to set up GPG signing for git commits, you’ll know it can be a fairly painful experience.&lt;/p&gt;
&lt;p&gt;As you can now sign git commits with SSH keys rather than GPG and given that pretty much everyone already has an SSH key (and pretty much no one has a GPG key properly configured) - this is a much more practical approach.&lt;/p&gt;
&lt;p&gt;Caleb Hearth has written an &lt;a href=&quot;https://calebhearth.com/sign-git-with-ssh&quot;&gt;excellent post on how to set this up&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’re using GitHub, you’ll need to upload your SSH key separately as a signing key (distinct from your authentication key) - but once that’s done you’ll get the verified badge on your commits.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Adobe Commerce Isolated Security Patches Changelog</title>
    
    <link href="https://dor.ky/posts/2026/01/adobe-commerce-isolated-security-patches-changelog/" rel="alternate" type="text/html"/>
    
    <updated>2026-01-12T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2026/01/adobe-commerce-isolated-security-patches-changelog/</id>
    <content type="html">&lt;p&gt;Adobe have changed the way they usually release security patch updates for&lt;br&gt;
2026, but sadly their communcations around the release leaves quite a bit&lt;br&gt;
to be desired.&lt;/p&gt;
&lt;p&gt;I’ll collate the release information here through the year and document&lt;br&gt;
what has/hasn’t been released as per the &lt;a href=&quot;https://experienceleague.adobe.com/en/docs/commerce-operations/release/planning/schedule&quot;&gt;official release schedule&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;13/01/2026: No patches released, confirmed by &lt;a href=&quot;https://magentocommeng.slack.com/archives/CANPJTBC5/p1768322442816999&quot;&gt;Nathan Smith via Slack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;10/02/2026: There was a release planned but then was revoked. Currently no release planned.&lt;/p&gt;
&lt;p&gt;10/03/2026: Pending&lt;/p&gt;
&lt;p&gt;14/04/2026: Pending&lt;/p&gt;
&lt;p&gt;12/05/2026: Pending, should be full semver release (well, Adobe’s attempt at it).&lt;/p&gt;
&lt;p&gt;09/06/2026: Pending&lt;/p&gt;
&lt;p&gt;14/07/2026: Pending&lt;/p&gt;
&lt;p&gt;11/08/2026: Pending&lt;/p&gt;
&lt;p&gt;08/09/2026: Pending&lt;/p&gt;
&lt;p&gt;13/10/2026: Pending&lt;/p&gt;
&lt;p&gt;10/11/2026: Pending&lt;/p&gt;
&lt;p&gt;08/12/2026: Pending&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Adobe Commerce Deployments Failing - Composer block-insecure in Effect for 2.7/2.8</title>
    
    <link href="https://dor.ky/posts/2026/01/adobe-commerce-deployments-failing-composer-block-insecure-in-effect-for-27-28/" rel="alternate" type="text/html"/>
    
    <updated>2026-01-02T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2026/01/adobe-commerce-deployments-failing-composer-block-insecure-in-effect-for-27-28/</id>
    <content type="html">&lt;p&gt;If you’re running into this issue with Adobe Commerce deployments, it’s due to the older versions of &lt;code&gt;composer&lt;/code&gt; now being marked as having a few security issues (“PKSA-1gck-s111-yq7g”, “PKSA-b8f7-zn44-r4gz”, “PKSA-s25b-vbmp-jvhh”):&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;Installing build dependencies&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br&gt;  Installing php build dependencies: composer/composer&lt;br&gt;  W: Changed current directory to /app/.global/composer/composer&lt;br&gt;  W: No composer.lock &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt; present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;more&lt;/span&gt; information.&lt;br&gt;  W: Loading composer repositories with package information&lt;br&gt;  W: Updating dependencies&lt;br&gt;  W: Your requirements could not be resolved to an installable &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; of packages.&lt;br&gt;  W:&lt;br&gt;  W:   Problem &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br&gt;  W:     - Root composer.json requires composer/composer &lt;span class=&quot;token number&quot;&gt;2.7&lt;/span&gt;.0 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;exact version match: &lt;span class=&quot;token number&quot;&gt;2.7&lt;/span&gt;.0 or &lt;span class=&quot;token number&quot;&gt;2.7&lt;/span&gt;.0.0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;, found composer/composer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2.7&lt;/span&gt;.0&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; but these were not loaded, because they are affected by security advisories. To ignore the advisories, &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;PKSA-1gck-s111-yq7g&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;PKSA-b8f7-zn44-r4gz&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;PKSA-s25b-vbmp-jvhh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; to the audit &lt;span class=&quot;token string&quot;&gt;&quot;ignore&quot;&lt;/span&gt; config. To turn the feature off entirely, you can &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;block-insecure&quot;&lt;/span&gt; to &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; your &lt;span class=&quot;token string&quot;&gt;&quot;audit&quot;&lt;/span&gt; config.&lt;br&gt;  W:&lt;br&gt;&lt;br&gt;E: Error building project: &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;composer&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt; could not be run.&lt;br&gt;&lt;br&gt;E: Error: Unable to build application, aborting.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To fix the issue, update the version of &lt;code&gt;composer&lt;/code&gt; used to build your project in the &lt;code&gt;.magento.app.yaml&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token key atrule&quot;&gt;php&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token key atrule&quot;&gt;composer/composer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;^2.9&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Magento 2.4.7 and up, use &lt;code&gt;^2.9&lt;/code&gt;, for anything else use &lt;code&gt;^2.2&lt;/code&gt; which should give you &lt;code&gt;2.2.26&lt;/code&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Nginx client_header_buffer_size - Debugging Cloudflare-related 400 Errors for Magento/Adobe Commerce HTTP Requests</title>
    
    <link href="https://dor.ky/posts/2025/12/nginx-400-error-webhook-response-debugging-for-adobe-commerce-cloudflare/" rel="alternate" type="text/html"/>
    
    <updated>2025-12-24T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2025/12/nginx-400-error-webhook-response-debugging-for-adobe-commerce-cloudflare/</id>
    <content type="html">&lt;p&gt;One of the more interesting things I’ve had to debug this year was why Magento&lt;br&gt;
was apparently returning &lt;code&gt;400&lt;/code&gt; responses to &lt;a href=&quot;https://builder.io/&quot;&gt;builder.io&lt;/a&gt; for certain webhook payloads.&lt;/p&gt;
&lt;p&gt;A few of the team had looked into this but drawn a bit of a blank so I offered to take a look and it ended up being a fairly puzzling one to debug.&lt;/p&gt;
&lt;p&gt;The same payload &lt;code&gt;POST&lt;/code&gt; direct to a local running version of the application would give the expected &lt;code&gt;200&lt;/code&gt; response, but when running through it’s production stack of Cloudflare and into the excellent &lt;a href=&quot;https://www.corefinity.com/&quot;&gt;Corefinity&lt;/a&gt; - we suddently started getting &lt;code&gt;400&lt;/code&gt; response codes which was fairly odd as the custom  controller that was receiving the payload had no code in it to return a &lt;code&gt;400&lt;/code&gt; response.&lt;/p&gt;
&lt;p&gt;My first thought was that Cloudflare was stopping the requests going due to either the body content or an OWASP ruleset. Running the requests through in no-proxy mode discounted this as being the issue.&lt;/p&gt;
&lt;p&gt;A fairly important piece of debugging spotted that the &lt;code&gt;nginx&lt;/code&gt; log presented the &lt;code&gt;400&lt;/code&gt; error as well, so that ruled out Cloudflare being the issue.&lt;/p&gt;
&lt;p&gt;I added some ancillary logging to fire whenever the controller Magento side fired to determine whether or not the request was even getting that far and fairly quickly realised that they weren’t even hitting Magento to return a &lt;code&gt;400&lt;/code&gt; response.&lt;/p&gt;
&lt;p&gt;My thoughts then shifted to either PHP’s &lt;code&gt;post_max_size&lt;/code&gt;, or perhaps&lt;br&gt;
&lt;code&gt;max_input_vars&lt;/code&gt; set to low and the payload couldn’t be parsed. The additional logging never fired when the &lt;code&gt;400&lt;/code&gt; was being returned so that pointed to &lt;code&gt;nginx&lt;/code&gt; or &lt;code&gt;varnish&lt;/code&gt; being the culprit.&lt;/p&gt;
&lt;p&gt;At this point, I trapped a few of the outbound &lt;code&gt;POST&lt;/code&gt; requests again and spotted that once they’d been through Cloudflare there was quite a number of headers and suspected that the issue we were actually running into was that nginx’s two configuration values were too low for:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;client_header_buffer_size&lt;/code&gt;&lt;br&gt;
&lt;code&gt;large_client_header_buffers&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This turned out to be the case, once these were increased the &lt;code&gt;400&lt;/code&gt; errors soon&lt;br&gt;
disappeared. We did also debug whether varnish was involved but fairly quickly&lt;br&gt;
ruled out that being part of the issue. It was solely nginx.&lt;/p&gt;
&lt;p&gt;If you ever encounter add odd &lt;code&gt;400&lt;/code&gt; response for a webhook on any host, I can highly recommend that you check those two configuration values first and with a bit of luck I’ve saved you some debugging.&lt;/p&gt;
&lt;p&gt;The best piece of advice I can give you is to isolate the point inside the stack you’re getting to when the &lt;code&gt;400&lt;/code&gt; is thrown, that will help you narrow down what the cause is quickly.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Adobe Commerce/Magento 2 Concurrent Import Process Interference Issue</title>
    
    <link href="https://dor.ky/posts/2025/12/adobe-commerce-magento2-issue-running-concurrent-imports/" rel="alternate" type="text/html"/>
    
    <updated>2025-12-04T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2025/12/adobe-commerce-magento2-issue-running-concurrent-imports/</id>
    <content type="html">&lt;p&gt;If you’re running multiple import processes simultaneously in Adobe Commerce or Magento 2, you might encounter a frustrating bug where the imports interfere with each other, causing data corruption or import failures. This issue, documented in &lt;a href=&quot;https://github.com/magento/magento2/issues/37593&quot;&gt;GitHub issue #37593&lt;/a&gt;, has been confirmed in Magento 2.4.6 but is present in other versions too namely 2.4.7.&lt;/p&gt;
&lt;p&gt;If two import processes run concurrently in Magento 2.4.6, they can interfere with each other in unexpected ways. For example, if you’re simultaneously importing customers and products, product data might erroneously appear in the customer import process, causing failures. I discovered this while debugging a customer importer that ended up being fed stock source import data.&lt;/p&gt;
&lt;p&gt;The issue stems from how Magento handles large import files using the &lt;code&gt;importexport_importdata&lt;/code&gt; table. The default batch size limit is set to 100 records in &lt;code&gt;vendor/magento/module-import-export/etc/config.xml&lt;/code&gt;. When an import exceeds this threshold, Magento splits the data across multiple rows in the database table and this is fed into the import&lt;br&gt;
engine.&lt;/p&gt;
&lt;p&gt;The problem occurs when concurrent imports add their validated data simultaneously to this shared table. Processes can then retrieve mixed or incorrect data from other running imports, leading to validation errors and data corruption.&lt;/p&gt;
&lt;h2 id=&quot;reproduction&quot;&gt;Reproduction&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;- Open Magento admin in two separate browser sessions or systems
- Navigate to System &amp;gt; Data Transfer &amp;gt; Import in both
- In the first session: Select &amp;quot;Customers and Addresses&amp;quot; with 500+ records
- In the second session: Select &amp;quot;Catalog Product Import&amp;quot; with 50-60 records
- Validate both imports
- Click Import on the first system, then immediately click Import on the second
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s fixed in &lt;a href=&quot;https://github.com/magento/magento2/commit/c4a868c0098379ab260bbc54f9a54267830dd0aa&quot;&gt;this commit&lt;/a&gt; which was pushed out in 2.4.8. For 2.4.7, Adobe have provided this &lt;code&gt;ACSD-63793_2.4.7-p3_v2.patch&lt;/code&gt; patch:&lt;/p&gt;
&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;diff --git a/vendor/magento/module-import-export/Block/Adminhtml/Import/Edit/Form.php b/vendor/magento/module-import-export/Block/Adminhtml/Import/Edit/Form.php&lt;br&gt;index bf394c9ed0c42..11eaaa1a4a202 100644&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;--- a/vendor/magento/module-import-export/Block/Adminhtml/Import/Edit/Form.php&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;+++ b/vendor/magento/module-import-export/Block/Adminhtml/Import/Edit/Form.php&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;@@ -1,7 +1,7 @@&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt; &amp;lt;?php&lt;br&gt; /**&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;- * Copyright © Magento, Inc. All rights reserved.&lt;br&gt;- * See COPYING.txt for license details.&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+ * Copyright 2013 Adobe&lt;br&gt;+ * All Rights Reserved.&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;  */&lt;br&gt; namespace Magento\ImportExport\Block\Adminhtml\Import\Edit;&lt;br&gt; &lt;br&gt;&lt;/span&gt;@@ -264,6 +264,16 @@ protected function _prepareForm()&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt;                 &#39;value&#39; =&gt; &#39;&#39;,&lt;br&gt;             ]&lt;br&gt;         );&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+        $fieldset-&gt;addField(&lt;br&gt;+            &#39;_import_history_id&#39;,&lt;br&gt;+            &#39;hidden&#39;,&lt;br&gt;+            [&lt;br&gt;+                &#39;name&#39; =&gt; &#39;_import_history_id&#39;,&lt;br&gt;+                &#39;label&#39; =&gt; __(&#39;Import History id&#39;),&lt;br&gt;+                &#39;title&#39; =&gt; __(&#39;Import History id&#39;),&lt;br&gt;+                &#39;value&#39; =&gt; &#39;&#39;,&lt;br&gt;+            ]&lt;br&gt;+        );&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;         $fieldsets[&#39;upload&#39;] = $fieldset;&lt;br&gt;         $form-&gt;setUseContainer(true);&lt;br&gt;         $this-&gt;setForm($form);&lt;br&gt;&lt;/span&gt;diff --git a/vendor/magento/module-import-export/Controller/Adminhtml/Import/Validate.php b/vendor/magento/module-import-export/Controller/Adminhtml/Import/Validate.php&lt;br&gt;index c388851edcbe4..bf0758bb2105c 100644&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;--- a/vendor/magento/module-import-export/Controller/Adminhtml/Import/Validate.php&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;+++ b/vendor/magento/module-import-export/Controller/Adminhtml/Import/Validate.php&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;@@ -1,7 +1,7 @@&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt; &amp;lt;?php&lt;br&gt; /**&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;- * Copyright © Magento, Inc. All rights reserved.&lt;br&gt;- * See COPYING.txt for license details.&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+ * Copyright 2011 Adobe&lt;br&gt;+ * All Rights Reserved.&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;  */&lt;br&gt; declare(strict_types=1);&lt;br&gt; &lt;br&gt;&lt;/span&gt;@@ -50,6 +50,11 @@ public function execute()&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt;                 $ids = $import-&gt;getValidatedIds();&lt;br&gt;                 if (count($ids) &gt; 0) {&lt;br&gt;                     $resultBlock-&gt;addAction(&#39;value&#39;, Import::FIELD_IMPORT_IDS, $ids);&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+                    $resultBlock-&gt;addAction(&lt;br&gt;+                        &#39;value&#39;,&lt;br&gt;+                        &#39;_import_history_id&#39;,&lt;br&gt;+                        $this-&gt;historyModel-&gt;getId()&lt;br&gt;+                    );&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;                 }&lt;br&gt;             } catch (\Magento\Framework\Exception\LocalizedException $e) {&lt;br&gt;                 $resultBlock-&gt;addError($e-&gt;getMessage());&lt;br&gt;&lt;/span&gt;diff --git a/vendor/magento/module-import-export/Model/History.php b/vendor/magento/module-import-export/Model/History.php&lt;br&gt;index 9a97367ba8453..ad0be7fbb8bc1 100644&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;--- a/vendor/magento/module-import-export/Model/History.php&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;+++ b/vendor/magento/module-import-export/Model/History.php&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;@@ -1,7 +1,7 @@&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt; &amp;lt;?php&lt;br&gt; /**&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;- * Copyright © Magento, Inc. All rights reserved.&lt;br&gt;- * See COPYING.txt for license details.&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+ * Copyright 2015 Adobe&lt;br&gt;+ * All Rights Reserved.&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;  */&lt;br&gt; namespace Magento\ImportExport\Model;&lt;br&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token coord&quot;&gt;@@ -9,33 +9,34 @@&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt;  * Import history model&lt;br&gt;  *&lt;br&gt;  * @api&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)&lt;br&gt;  * @SuppressWarnings(PHPMD.LongVariable)&lt;br&gt;  * @since 100.0.2&lt;br&gt;  */&lt;br&gt; class History extends \Magento\Framework\Model\AbstractModel&lt;br&gt; {&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const HISTORY_ID = &#39;history_id&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const HISTORY_ID = &#39;history_id&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const STARTED_AT = &#39;started_at&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const STARTED_AT = &#39;started_at&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const USER_ID = &#39;user_id&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const USER_ID = &#39;user_id&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const IMPORTED_FILE = &#39;imported_file&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const IMPORTED_FILE = &#39;imported_file&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const ERROR_FILE = &#39;error_file&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const ERROR_FILE = &#39;error_file&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const EXECUTION_TIME = &#39;execution_time&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const EXECUTION_TIME = &#39;execution_time&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const SUMMARY = &#39;summary&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const SUMMARY = &#39;summary&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const IMPORT_IN_PROCESS = &#39;In Progress&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const IMPORT_IN_PROCESS = &#39;In Progress&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const IMPORT_VALIDATION = &#39;Validation&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const IMPORT_VALIDATION = &#39;Validation&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const IMPORT_FAILED = &#39;Failed&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const IMPORT_FAILED = &#39;Failed&#39;;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-    const IMPORT_SCHEDULED_USER = 0;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+    public const IMPORT_SCHEDULED_USER = 0;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;     /**&lt;br&gt;      * @var \Magento\ImportExport\Helper\Report&lt;br&gt;&lt;/span&gt;@@ -122,7 +123,7 @@ public function addErrorReportFile($filename)&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt;     public function updateReport(Import $import, $updateSummary = false)&lt;br&gt;     {&lt;br&gt;         if ($import-&gt;isReportEntityType()) {&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;-            $this-&gt;load($this-&gt;getLastItemId());&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+            $this-&gt;load($import-&gt;getData(&#39;_import_history_id&#39;) ?? $this-&gt;getLastItemId());&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;             $executionResult = self::IMPORT_IN_PROCESS;&lt;br&gt;             if ($updateSummary) {&lt;br&gt;                 $executionResult = $this-&gt;reportHelper-&gt;getExecutionTime($this-&gt;getStartedAt());&lt;br&gt;&lt;/span&gt;diff --git a/vendor/magento/module-import-export/i18n/en_US.csv b/vendor/magento/module-import-export/i18n/en_US.csv&lt;br&gt;index cc1098841bab8..378daac3afa25 100644&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;--- a/vendor/magento/module-import-export/i18n/en_US.csv&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;+++ b/vendor/magento/module-import-export/i18n/en_US.csv&lt;/span&gt;&lt;br&gt;@@ -29,6 +29,7 @@ Import,Import&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt; &quot;File to Import&quot;,&quot;File to Import&quot;&lt;br&gt; &quot;Select File to Import&quot;,&quot;Select File to Import&quot;&lt;br&gt; &quot;Images File Directory&quot;,&quot;Images File Directory&quot;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+&quot;Import History id&quot;,&quot;Import History id&quot;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt; &quot;For Type &quot;&quot;Local Server&quot;&quot; use relative path to &amp;amp;lt;Magento root directory&amp;amp;gt;/var/import/images, e.g. &amp;lt;i&gt;product_images&amp;lt;/i&gt;, &amp;lt;i&gt;import_images/batch1&amp;lt;/i&gt;.&amp;lt;br&gt;&amp;lt;br&gt;For example, in case &amp;lt;i&gt;product_images&amp;lt;/i&gt;, files should be placed into &amp;lt;i&gt;&amp;amp;lt;Magento root directory&amp;amp;gt;/var/import/images/product_images&amp;lt;/i&gt; folder.&quot;,&quot;For Type &quot;&quot;Local Server&quot;&quot; use relative path to &amp;amp;lt;Magento root directory&amp;amp;gt;/var/import/images, e.g. &amp;lt;i&gt;product_images&amp;lt;/i&gt;, &amp;lt;i&gt;import_images/batch1&amp;lt;/i&gt;.&amp;lt;br&gt;&amp;lt;br&gt;For example, in case &amp;lt;i&gt;product_images&amp;lt;/i&gt;, files should be placed into &amp;lt;i&gt;&amp;amp;lt;Magento root directory&amp;amp;gt;/var/import/images/product_images&amp;lt;/i&gt; folder.&quot;&lt;br&gt; &quot;Download Sample File&quot;,&quot;Download Sample File&quot;&lt;br&gt; &quot;Please correct the data sent value.&quot;,&quot;Please correct the data sent value.&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As noted earlier, there’s more discussion and info on &lt;a href=&quot;https://github.com/magento/magento2/issues/37593&quot;&gt;GitHub Issue #37593&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to List/Change/Activate Different Service Versions on Fastly for Adobe Commerce</title>
    
    <link href="https://dor.ky/posts/2025/11/adobe-commerce-fastly-change-or-activate-different-service-version/" rel="alternate" type="text/html"/>
    
    <updated>2025-11-23T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2025/11/adobe-commerce-fastly-change-or-activate-different-service-version/</id>
    <content type="html">&lt;p&gt;There are times when you need to either list or activate an old version of your&lt;br&gt;
Fastly configuration but you may not be able to access your Magento/Adobe Commerce&lt;br&gt;
control panel to do so.&lt;/p&gt;
&lt;p&gt;If you need to list versions of your service, you can do so using the Fastly CLI&lt;br&gt;
tool using:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;fastly service-version list -t API_KEY -s SERVICE_ID&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will return you a list of service versions and their associated dates:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NUMBER  ACTIVE  STAGED  LAST EDITED (UTC)
1        false    false    2020-06-09 17:25
2        false    false    2020-06-09 21:01
3        false    false    2020-06-10 00:08
4        false    false    2020-06-10 02:27
5        false    false    2020-06-10 06:40
6        false    false    2020-06-10 09:02
7        false    false    2020-06-11 16:07
8        false    false    2020-06-25 20:02
9        false    false    2020-06-25 20:02
10       false    false    2020-07-13 08:42
11       false    false    2020-07-13 08:43
12       false    false    2020-07-22 10:09
13       false    false    2020-07-28 20:07
14       false    false    2020-07-28 19:51
15       false    false    2020-08-03 12:04
16       false    false    2020-09-29 20:04
17       false    false    2020-10-02 12:03
18       false    false    2020-10-29 21:32
19       false    false    2020-12-01 12:03
20       false    false    2021-01-07 12:57
21       false    false    2021-01-07 12:58
22       false    false    2021-01-07 12:59
23       false    false    2021-01-07 13:01
24       false    false    2021-01-30 08:05
25       false    false    2021-02-16 10:41
26       false    false    2021-02-17 09:17
27       false    false    2021-03-18 14:29
28       false    false    2021-03-31 08:04
29       false    false    2021-05-06 10:14
30       false    false    2021-05-10 10:08
31       false    false    2021-05-10 10:09
32       false    false    2021-05-12 14:01
33       false    false    2021-05-30 08:05
34       false    false    2021-06-07 21:07
35       false    false    2021-06-07 21:19
36       false    false    2021-07-16 10:08
37       false    false    2021-07-16 11:11
38       false    false    2021-07-29 08:04
39       false    false    2021-09-27 08:05
40       false    false    2021-11-10 16:15
41       false    false    2021-11-11 17:39
42       false    false    2021-11-15 11:52
43       false    false    2021-11-26 08:04
44       false    false    2021-12-09 11:28
45       false    false    2022-01-25 08:04
46       false    false    2022-01-28 09:34
47       false    false    2022-02-08 16:30
48       false    false    2022-03-08 10:46
49       false    false    2022-03-26 08:04
50       false    false    2022-03-29 01:53
51       false    false    2022-04-19 12:27
52       false    false    2022-05-18 08:30
53       false    false    2022-05-25 08:04
54       false    false    2022-07-24 08:03
55       false    false    2022-07-24 08:03
56       false    false    2022-08-17 13:23
57       false    false    2022-09-20 08:21
58       false    false    2022-09-22 08:04
59       false    false    2022-09-27 13:47
60       false    false    2022-09-27 13:56
61       false    false    2022-09-28 09:11
62       false    false    2022-10-03 09:02
63       false    false    2022-10-19 13:56
64       false    false    2022-11-21 08:02
65       false    false    2022-12-06 05:43
66       false    false    2022-12-08 15:14
67       false    false    2022-12-13 09:31
68       false    false    2022-12-13 09:34
69       false    false    2022-12-22 16:00
70       false    false    2022-12-22 16:04
71       false    false    2023-01-20 08:03
72       false    false    2023-01-27 12:45
73       false    false    2023-02-23 16:15
74       false    false    2023-03-21 08:02
75       false    false    2023-04-21 16:07
76       false    false    2023-04-21 16:34
77       false    false    2023-04-21 16:46
78       false    false    2023-04-21 18:25
79       false    false    2023-04-21 20:16
80       false    false    2023-04-22 11:53
81       false    false    2023-04-22 12:03
82       false    false    2023-04-24 09:39
83       false    false    2023-04-24 09:55
84       false    false    2023-04-24 09:56
85       false    false    2023-04-24 10:00
86       false    false    2023-04-24 10:07
87       false    false    2023-04-27 13:05
88       false    false    2023-04-27 13:07
89       false    false    2023-05-02 08:35
90       false    false    2023-05-02 10:22
91       false    false    2023-05-20 08:04
92       false    false    2023-05-24 17:20
93       false    false    2023-05-25 09:28
94       false    false    2023-05-31 18:13
95       false    false    2023-07-06 12:34
96       false    false    2023-07-19 08:05
97       false    false    2023-08-15 09:41
98       false    false    2023-08-15 09:41
99       false    false    2023-08-15 10:51
100      false    false    2023-08-15 10:52
101      false    false    2023-08-15 14:31
102      false    false    2023-08-22 07:08
103      false    false    2023-08-22 13:45
104      false    false    2023-08-22 15:21
105      false    false    2023-08-22 15:26
106      false    false    2023-08-22 15:25
107      false    false    2023-08-22 15:25
108      false    false    2023-09-06 21:37
109      false    false    2023-08-22 15:26
110      false    false    2023-09-15 13:28
111      false    false    2023-09-15 13:38
112      false    false    2023-09-17 08:04
113      false    false    2023-09-23 05:36
114      false    false    2023-09-23 05:49
115      false    false    2023-09-23 06:12
116      false    false    2023-09-25 06:09
117      false    false    2023-10-05 05:58
118      false    false    2023-10-05 06:35
119      false    false    2023-10-05 09:06
120      false    false    2023-10-05 09:08
121      false    false    2023-10-05 09:09
122      false    false    2023-10-05 09:29
123      false    false    2023-10-27 07:20
124      false    false    2023-11-07 14:24
125      false    false    2023-11-16 08:04
126      false    false    2023-11-20 12:45
127      false    false    2023-12-12 08:05
128      false    false    2023-12-13 17:57
129      false    false    2024-01-15 08:04
130      false    false    2024-03-01 10:44
131      false    false    2024-03-15 08:05
132      false    false    2024-04-10 14:16
133      false    false    2024-04-10 14:20
134      false    false    2024-05-02 18:39
135      false    false    2024-05-14 08:05
136      false    false    2024-05-17 10:23
137      false    false    2024-05-17 10:26
138      false    false    2024-05-17 10:31
139      false    false    2024-05-17 10:34
140      false    false    2024-05-17 12:24
141      false    false    2024-05-17 12:25
142      false    false    2024-05-17 12:28
143      false    false    2024-05-21 09:11
144      false    false    2024-05-21 09:17
145      false    false    2024-05-21 09:30
146      false    false    2024-05-21 09:30
147      false    false    2024-05-21 12:22
148      false    false    2024-06-03 10:03
149      false    false    2024-06-19 06:07
150      false    false    2024-06-28 06:55
151      false    false    2024-07-05 12:05
152      false    false    2024-07-08 07:14
153      false    false    2024-07-08 11:52
154      false    false    2024-07-09 07:25
155      false    false    2024-07-13 08:03
156      false    false    2024-07-19 06:28
157      false    false    2024-07-19 06:57
158      false    false    2024-07-22 11:32
159      false    false    2024-08-16 12:39
160      false    false    2024-09-11 08:04
161      false    false    2024-09-25 17:58
162      false    false    2024-10-14 21:41
163      false    false    2024-10-22 07:29
164      false    false    2024-10-22 22:09
165      false    false    2024-11-10 08:04
166      false    false    2024-11-13 14:30
167      false    false    2024-11-22 08:03
168      false    false    2024-12-17 08:42
169      false    false    2024-12-22 03:13
170      false    false    2024-12-22 03:58
171      false    false    2025-01-09 08:04
172      false    false    2024-12-22 03:53
173      false    false    2025-01-29 21:54
174      false    false    2025-01-29 21:54
175      false    false    2025-02-13 14:20
176      false    false    2025-03-10 08:05
177      false    false    2025-03-21 08:44
178      false    false    2025-03-21 12:03
179      false    false    2025-03-21 15:12
180      false    false    2025-03-21 15:13
181      false    false    2025-03-25 23:02
182      false    false    2025-05-08 16:36
183      false    false    2025-05-09 08:03
184      false    false    2025-05-15 16:18
185      false    false    2025-05-21 11:16
186      false    false    2025-05-24 13:15
187      false    false    2025-06-11 13:24
188      false    false    2025-07-08 08:03
189      false    false    2025-07-29 16:18
190      false    false    2025-08-06 16:26
191      false    false    2025-09-05 14:48
192      false    false    2025-09-06 08:04
193      false    false    2025-09-08 17:38
194      false    false    2025-09-11 22:18
195      false    false    2025-09-22 07:00
196      false    false    2025-09-22 23:59
197      false    false    2025-10-14 16:04
198      false    false    2025-10-20 12:13
199      false    false    2025-10-20 13:25
200      false    false    2025-10-21 12:16
201      false    false    2025-11-05 08:04
202      false    false    2025-11-20 10:58
203      false    false    2025-11-20 10:46
204      false    false    2025-11-20 11:30
205      false    false    2025-11-20 11:53
206      true     false    2025-11-20 11:53
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From here, you can activate one of those versions by running this command:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;fastly service-version activate --version&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;204&lt;/span&gt; -t API_KEY -s SERVICE_ID&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can fetch both your API_KEY key and SERVICE_ID from the file mounted at:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;/mnt/shared/fastly_tokens.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in your Commerce Cloud cluster if you don’t have the tokens to hand.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Flush Fastly CDN via CLI/Command Line for Adobe Commerce Projects</title>
    
    <link href="https://dor.ky/posts/2025/11/flush-adobe-commerce-fastly-cdn-via-curl/" rel="alternate" type="text/html"/>
    
    <updated>2025-11-16T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2025/11/flush-adobe-commerce-fastly-cdn-via-curl/</id>
    <content type="html">&lt;p&gt;If you ever need the ability to flush Fastly but can’t acess an Adobe Commerce&lt;br&gt;
admin panel to do so, you can run the following curl request:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; -H &lt;span class=&quot;token string&quot;&gt;&quot;Fastly-Key: API_KEY” -X POST &quot;&lt;/span&gt;https://api.fastly.com/service/SERVICE_ID/purge_all&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can fetch both your API_KEY key and SERVICE_ID from the file mounted at:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;/mnt/shared/fastly_tokens.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in your Commerce Cloud cluster.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Adobe Commerce Deployment issue &#39;does not support Valkey backend model&#39;</title>
    
    <link href="https://dor.ky/posts/2025/04/valkey-error-adobe-commerce-deployments/" rel="alternate" type="text/html"/>
    
    <updated>2025-04-13T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2025/04/valkey-error-adobe-commerce-deployments/</id>
    <content type="html">&lt;p&gt;If you’ve recently deployed one of the latest release lines of Magento on Commerce Cloud and have:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;REDIS_BACKEND&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;\Magento\Framework\Cache\Backend\RemoteSynchronizedCache&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2025&lt;/span&gt;-04-08T10:29:29.486342+00:00&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;br&gt;ERROR: Magento version &lt;span class=&quot;token string&quot;&gt;&#39;2.4.7.0-patch5&#39;&lt;/span&gt; does not support Valkey backend &lt;br&gt;model &lt;span class=&quot;token string&quot;&gt;&#39;\Magento\Framework\Cache\Backend\RemoteSynchronizedCache&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a &lt;a href=&quot;https://github.com/magento/ece-tools/issues/824&quot;&gt;Github issue for this problem&lt;/a&gt;. That&lt;br&gt;
latest release of &lt;code&gt;ece-tools&lt;/code&gt; does have a fix for the issue albeit not a great fix.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Adobe Commerce B2B upgrade issue &#39;REGEXP_LIKE does not exist&#39;</title>
    
    <link href="https://dor.ky/posts/2025/04/adobe-commerce-b2b-upgrade-error/" rel="alternate" type="text/html"/>
    
    <updated>2025-04-13T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2025/04/adobe-commerce-b2b-upgrade-error/</id>
    <content type="html">&lt;p&gt;If you’re using Adobe’s B2B extension and recently tried upgrading then you likely hit this issue:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;W: Unable to apply data patch Magento&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Company&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Setup&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Patch&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Data&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;SetComp&lt;br&gt;W: anyForStructure &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; module Magento_Company. Original exception message: SQL&lt;br&gt;W: STATE&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;42000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;: Syntax error or access violation: &lt;span class=&quot;token number&quot;&gt;1305&lt;/span&gt; FUNCTION abcdefghijk &lt;br&gt;W: .REGEXP_LIKE does not exist, query was: UPDATE &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;company_structure&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt; SET &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;com&lt;br&gt;W: pany_id&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ? WHERE &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;REGEXP_LIKE&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path, &lt;span class=&quot;token string&quot;&gt;&#39;^7(/.+)?$&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I sent this in to Adobe’s Cloud support and got this Absolute gem of a response from support:&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;We investigated this further and please find more details regarding this error below:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;W: Unable to apply data patch Magento\Company\Setup\Patch\Data\SetComp&lt;br&gt;
W: anyForStructure for module Magento_Company. Original exception message: SQL&lt;br&gt;
W: STATE[42000]: Syntax error or access violation: 1305 FUNCTION abcdefghijk&lt;br&gt;
W: .REGEXP_LIKE does not exist, query was: UPDATE &lt;code&gt;company_structure&lt;/code&gt; SET &lt;code&gt;com W: pany_id&lt;/code&gt; = ? WHERE (REGEXP_LIKE(path, ‘^7(/.+)?$’))&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The Adobe Commerce version 2.4.6-p10 uses the function “REGEXP_LIKE” in the file \Magento\Company\Setup\Patch\Data\SetCompanyForStructure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The function “REGEXP_LIKE” is not supported in hashtag MariaDB which is the default Database used by Adobe Commerce.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No idea how this one got through QA.&lt;/p&gt;
&lt;p&gt;If you pin the version of the B2B extension to &lt;code&gt;1.4.2-p3&lt;/code&gt; it’ll work or you could patch out that function.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel 12 $request-&gt;getContentType() does not exist</title>
    
    <link href="https://dor.ky/posts/2025/04/laravel-guzzle-getcontenttype-method-does-not-exist/" rel="alternate" type="text/html"/>
    
    <updated>2025-04-12T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2025/04/laravel-guzzle-getcontenttype-method-does-not-exist/</id>
    <content type="html">&lt;p&gt;If you use Laravel’s Request object and had previously used the &lt;code&gt;$request-&amp;gt;getContentType()&lt;/code&gt; method&lt;br&gt;
then in Laravel 12, it’s been changed to &lt;code&gt;$request-&amp;gt;getContentTypeFormat()&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;Old:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;/**&lt;br&gt; *&lt;br&gt; */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ApiRequestHandler&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/**&lt;br&gt;     * @param Illuminate\Http\Request $request&lt;br&gt;     */&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__invoke&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;\&lt;span class=&quot;token package&quot;&gt;Illuminate&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Http&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Request&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContentType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;form&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;          &lt;span class=&quot;token comment&quot;&gt;// Do something&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;New:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;/**&lt;br&gt; *&lt;br&gt; */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ApiRequestHandler&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/**&lt;br&gt;     * @param Illuminate\Http\Request $request&lt;br&gt;     */&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__invoke&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;\&lt;span class=&quot;token package&quot;&gt;Illuminate&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Http&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Request&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContentTypeFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;form&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;          &lt;span class=&quot;token comment&quot;&gt;// Do something&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Set Website/Store Assignment via Magento 2 API</title>
    
    <link href="https://dor.ky/posts/2025/02/updating-store-website-assignment-magento2-api/" rel="alternate" type="text/html"/>
    
    <updated>2025-02-28T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2025/02/updating-store-website-assignment-magento2-api/</id>
    <content type="html">&lt;p&gt;If you need to update the website a product is assigned to in Magento via the&lt;br&gt;
REST API, you can do this fairly easily.&lt;/p&gt;
&lt;p&gt;You can get the current websites assigned by running this query:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://www.mystore.co.uk/rest/all/V1/products/MY-PRODUCT-SKU&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br&gt;     -H &lt;span class=&quot;token string&quot;&gt;&#39;Content-Type: application/json&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br&gt;     -H &lt;span class=&quot;token string&quot;&gt;&#39;Authorization: Bearer [token]&#39;&lt;/span&gt;&lt;br&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will return a JSON payload. Within the payload you’ll find:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5687&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;sku&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MY-PRODUCT-SKU&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;My Product&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;attribute_set_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;price&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9.99&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;visibility&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;type_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;simple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2024-03-07 13:45:29&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;updated_at&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2025-02-24 14:20:09&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;weight&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;extension_attributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;website_ids&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key part you’re looking for there is &lt;code&gt;website_ids&lt;/code&gt; within&lt;br&gt;
&lt;code&gt;extension_attributes&lt;/code&gt; which will give you the currently assigned website IDs.&lt;/p&gt;
&lt;p&gt;To set this data, you can make a &lt;code&gt;PUT&lt;/code&gt; request:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; -X &lt;span class=&quot;token string&quot;&gt;&quot;PUT&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://www.mystore.co.uk/rest/all/V1/products/MY-PRODUCT-SKU&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br&gt;     -H &lt;span class=&quot;token string&quot;&gt;&#39;Content-Type: application/json&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br&gt;     -H &lt;span class=&quot;token string&quot;&gt;&#39;Authorization: Bearer [token]&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br&gt;     -d $&lt;span class=&quot;token string&quot;&gt;&#39;{&lt;br&gt;  &quot;product&quot;: {&lt;br&gt;    &quot;extension_attributes&quot;: {&lt;br&gt;      &quot;website_ids&quot;: [&lt;br&gt;        1,&lt;br&gt;        3,&lt;br&gt;        14,&lt;br&gt;        22&lt;br&gt;      ]&lt;br&gt;    }&lt;br&gt;  }&lt;br&gt;}&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will then set the product to be in the given websites.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Can&#39;t place the order error for Paypal Express (when Stripe is also installed) with Magento 2</title>
    
    <link href="https://dor.ky/posts/2025/01/magento2-paypal-express-we-cant-place-order/" rel="alternate" type="text/html"/>
    
    <updated>2025-01-10T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2025/01/magento2-paypal-express-we-cant-place-order/</id>
    <content type="html">&lt;p&gt;This week I needed to debug an issue when Paypal Express was being used and it was throwing a “We can’t place the order”.&lt;/p&gt;
&lt;p&gt;If you’ve ever looked into the Paypal Express controller within Magento then you’ll see that it’s effectively a catch all when something in the process fails.&lt;/p&gt;
&lt;p&gt;If you take a look at &lt;code&gt;vendor/magento/module-paypal/Controller/Express/AbstractExpress/PlaceOrder.php&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token number&quot;&gt;141&lt;/span&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ApiProcessableException &lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;142&lt;/span&gt;            &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_processPaypalApiError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;143&lt;/span&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LocalizedException &lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;144&lt;/span&gt;            &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;processException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getRawMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;145&lt;/span&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;\&lt;span class=&quot;token package&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;146&lt;/span&gt;            &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;processException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;We can\&#39;t place the order.&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;147&lt;/span&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This bug presents itself when the user follows this process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Order an item that doesn’t have free shipping&lt;/li&gt;
&lt;li&gt;Guest user&lt;/li&gt;
&lt;li&gt;Using a PHP8.2 compatible version of Stripe &lt;code&gt;stripe/stripe-payments&lt;/code&gt; extension, in this case it was v3.5.16&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you imagine the customer going through this flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add item to cart that doesn’t have free shipping, let’s say £10.00 inc VAT.&lt;/li&gt;
&lt;li&gt;User uses a shortcut button to go and pay via Paypal Express&lt;/li&gt;
&lt;li&gt;The user authorises £10.00 at Paypal and then returns to the order review page&lt;/li&gt;
&lt;li&gt;At this point, they need to select shipping which we’ll say is £5 inc VAT.&lt;/li&gt;
&lt;li&gt;When the user now tries to place the order, the total required is £15.00 - not the pre authorised £10.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This causes Paypal to reject the transaction:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;Exception &lt;span class=&quot;token shell-comment comment&quot;&gt;#0 (Exception): PayPal gateway has rejected request. This transaction couldn&#39;t be completed. Please redirect your customer to PayPal (#10486: This transaction couldn&#39;t be completed).&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In normal working order, the Paypal extension then throws a &lt;code&gt;ApiProcessableException&lt;/code&gt; exception, which is then caught by line 141 in the code example above.&lt;/p&gt;
&lt;p&gt;Now, this is where it gets problematic. Stripe have a plugin located at &lt;code&gt;vendor/stripe/module-payments/Plugin/Sales/Model/Service/OrderService.php&lt;/code&gt; which has an &lt;code&gt;around&lt;/code&gt; on the &lt;code&gt;place()&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;aroundPlace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$subject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; \&lt;span class=&quot;token package&quot;&gt;Closure&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$proceed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getQuoteId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;quoteHelper&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;quoteId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getQuoteId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;        &lt;span class=&quot;token variable&quot;&gt;$savedOrder&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$proceed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;postProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$savedOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;\&lt;span class=&quot;token package&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token variable&quot;&gt;$helper&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;helperFactory&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token variable&quot;&gt;$msg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$helper&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isAuthenticationRequiredMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$helper&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dieWithError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem here is that Stripe are assuming they’re the only paypal in play that may throw an exception. They’re just blanket catching all exceptions and hoovering them up which then catches Paypal’s &lt;code&gt;ApiProcessableException&lt;/code&gt; exception as well - meaning the user is never redirected to Paypal to authorise the new amount of £15.00.&lt;/p&gt;
&lt;p&gt;For a company as big as Stripe, I’m genuinely surprised that they haven’t written this better or even checked that the current payment method in the process is actually a Stripe one. Defensive programming it is not.&lt;/p&gt;
&lt;p&gt;The patch is fairly simple:&lt;/p&gt;
&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;diff --git a/vendor/stripe/module-payments/Plugin/Sales/Model/Service/OrderService.php b/vendor/stripe/module-payments/Plugin/Sales/Model/Service/OrderService.php&lt;br&gt;index 1fe4d32e2..bdd6cb0f7 100644&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;--- a/vendor/stripe/module-payments/Plugin/Sales/Model/Service/OrderService.php&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token coord&quot;&gt;+++ b/vendor/stripe/module-payments/Plugin/Sales/Model/Service/OrderService.php&lt;/span&gt;&lt;br&gt;@@ -38,6 +38,10 @@ class OrderService&lt;br&gt;&lt;span class=&quot;token unchanged&quot;&gt; &lt;br&gt;     public function aroundPlace($subject, \Closure $proceed, $order)&lt;br&gt;     {&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;+        if (!str_contains($order-&gt;getPayment()-&gt;getMethod(), &quot;stripe_&quot;)) {&lt;br&gt;+            return $proceed($order);&lt;br&gt;+        }&lt;br&gt;+&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;         try&lt;br&gt;         {&lt;br&gt;             if (!empty($order) &amp;amp;&amp;amp; !empty($order-&gt;getQuoteId()))&lt;br&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just a check to make sure that the payment method being used is actually a Stripe one. This prevents the hoovering up on non-Stripe payment methods.&lt;/p&gt;
&lt;p&gt;There’s a few people who have bumped into similar issues on Github too &lt;a href=&quot;https://github.com/magento/magento2/issues/34412&quot;&gt;https://github.com/magento/magento2/issues/34412&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Hyva Not Generating app/etc/hyva-themes.json on Deployment for Magento 2.4.7</title>
    
    <link href="https://dor.ky/posts/2024/10/hyva-not-generating-hyva-themes-json-magento-2-4-7/" rel="alternate" type="text/html"/>
    
    <updated>2024-10-27T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2024/10/hyva-not-generating-hyva-themes-json-magento-2-4-7/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: Hyva are now recommending Adobe Commerce Cloud customers commit their &lt;code&gt;app/etc/hyva-themes.json&lt;/code&gt; file into the repo.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The app/etc/hyva-themes.json file&lt;br&gt;
The file needs to be generated after Magento is installed, so it can’t be run during the build phase. This means, for Adobe Commerce Cloud projects, the app/etc/&lt;br&gt;
hyva-themes.json file needs to be commited to the repository.&lt;br&gt;
Otherwise the file will be missing during the compilation of the styles.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and they’ve update &lt;a href=&quot;https://docs.hyva.io/hyva-themes/building-your-theme/adobe-commerce-cloud-deployment.html#the-appetchyva-themesjson-file&quot;&gt;the docs&lt;/a&gt; accordingly.&lt;/p&gt;
&lt;p&gt;If you don’t wish the commit that file into your repo, the initial solution in this post still works.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;At work this week I was updating the deployment scripts for one of our projects&lt;br&gt;
when I realised that Hyva wasn’t generating the &lt;code&gt;app/etc/hyva-themes.json&lt;/code&gt;&lt;br&gt;
file on deployment which then caused the pipeline to fail.&lt;/p&gt;
&lt;p&gt;This was due to two different things, there’s a bug in Hyva for Magento 2.4.7&lt;br&gt;
where it isn’t properly triggering a generation. That problem is fixed in an&lt;br&gt;
existing &lt;a href=&quot;https://gitlab.hyva.io/hyva-themes/magento2-theme-module/-/merge_requests/488&quot;&gt;Merge Request on Hyva’s Gitlab&lt;/a&gt; which solves the problem by triggering generation when &lt;code&gt;ConfigImportProcessor&lt;/code&gt; is intercepted (see MR for more).&lt;/p&gt;
&lt;p&gt;The second issue is more of a conceptual issue. The default instruction for&lt;br&gt;
&lt;a href=&quot;https://docs.hyva.io/hyva-themes/building-your-theme/adobe-commerce-cloud-deployment.html&quot;&gt;deploying on Adobe Commerce Cloud&lt;/a&gt; won’t work out the box for most Commerce&lt;br&gt;
Cloud deployments due to the ordering of deployment comamnds (where&lt;br&gt;
&lt;code&gt;app/etc/hyva-themes.json&lt;/code&gt; isn’t tracked in the repo).&lt;/p&gt;
&lt;p&gt;This is because the Hyva generation via NPM runs before one of the commands to&lt;br&gt;
trigger the writing of &lt;code&gt;app/etc/hyva-themes.json&lt;/code&gt;. At the time&lt;br&gt;
&lt;code&gt;npm run build-prod&lt;/code&gt; fires - there isn’t a &lt;code&gt;app/etc/hyva-themes.json&lt;/code&gt; written&lt;br&gt;
so the deployment will fail with something like this:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run build &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run output-success&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; @hyva-themes/magento2-default-theme@3.0.0 build&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;production npx tailwindcss --postcss -i tailwind-source.css -o &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/css/styles.css --minify&lt;br&gt;&lt;br&gt;W: node:fs:603&lt;br&gt;W:   handleErrorFromBinding&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;W:   ^&lt;br&gt;W: &lt;br&gt;W: Error: ENOENT: no such &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt; or directory, &lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/app/app/etc/hyva-themes.json&#39;&lt;/span&gt;&lt;br&gt;W:     at Object.openSync &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node:fs:603:3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;W:     at Object.readFileSync &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node:fs:471:35&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;W:     at Object.&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;anonymous&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;/app/app/design/frontend/Deploy/project/web/tailwind/node_modules/@hyva-themes/hyva-modules/src/index.js:107:19&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;W:     at Module._compile &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node:internal/modules/cjs/loader:1256:14&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;W:     at Module._extensions&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;js &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node:internal/modules/cjs/loader:1310:10&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;W:     at Module.load &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node:internal/modules/cjs/loader:1119:32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;W:     at Module._load &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node:internal/modules/cjs/loader:960:12&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;W:     at Module.require &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node:internal/modules/cjs/loader:1143:19&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;W:     at require &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node:internal/modules/cjs/helpers:121:18&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;W:     at Object.&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;anonymous&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;/app/app/design/frontend/Deploy/project/web/tailwind/postcss.config.js:1:38&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;W:   errno: -2,&lt;br&gt;W:   syscall: &lt;span class=&quot;token string&quot;&gt;&#39;open&#39;&lt;/span&gt;,&lt;br&gt;W:   code: &lt;span class=&quot;token string&quot;&gt;&#39;ENOENT&#39;&lt;/span&gt;,&lt;br&gt;W:   path: &lt;span class=&quot;token string&quot;&gt;&#39;/app/app/etc/hyva-themes.json&#39;&lt;/span&gt;&lt;br&gt;W: &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;W: &lt;br&gt;W: Node.js v18.17.1&lt;br&gt;&lt;br&gt;E: Error building project: Step failed with status code &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.&lt;br&gt;&lt;br&gt;E: Error: Unable to build application, aborting.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes sense, give the bug in Hyva with 2.4.7 not trigger the writing of&lt;br&gt;
the file, it can’t read from it as its not there.&lt;/p&gt;
&lt;p&gt;You can work around this by setting your build hook in &lt;code&gt;.magento.app.yaml&lt;/code&gt; to&lt;br&gt;
disable/enable one of the Hyva core extensions which triggers the writing of&lt;br&gt;
the required &lt;code&gt;app/etc/hyva-themes.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;hooks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token comment&quot;&gt;# We run build hooks before your application has been packaged.&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token key atrule&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;&lt;br&gt;    set -e&lt;br&gt;    composer --no-ansi --no-interaction install --no-progress --prefer-dist --optimize-autoloader --no-dev&lt;/span&gt;&lt;br&gt;    &lt;br&gt;    echo &#39;Generating app/etc/hyva&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;themes.json&#39;&lt;br&gt;    bin/magento module&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;disable Hyva_Theme &lt;span class=&quot;token important&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; bin/magento module&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;enable Hyva_Theme&lt;br&gt;    &lt;br&gt;    unset NPM_CONFIG_PREFIX&lt;br&gt;    curl &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//raw.githubusercontent.com/nvm&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;sh/nvm/v0.39.7/install.sh &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; bash&lt;br&gt;    export NVM_DIR=&quot;$HOME/.nvm&quot;    &lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;s &quot;$NVM_DIR/nvm.sh&quot;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token important&quot;&gt;&amp;amp;&amp;amp;.&lt;/span&gt; &quot;$NVM_DIR/nvm.sh&quot;&lt;br&gt;    nvm install 18.17&lt;br&gt;&lt;br&gt;    echo &#39;Generating Hyva styles&lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;&#39;&lt;br&gt;    mkdir &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;p app/design/frontend/Deploy/project/web/css/&lt;br&gt;    npm &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;prefix app/design/frontend/Deploy/project/web/tailwind/ install&lt;br&gt;    npm &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;prefix app/design/frontend/Deploy/project/web/tailwind/ run build&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;prod&lt;br&gt;    rm &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;rf app/design/frontend/Deploy/project/web/tailwind/node_modules/&lt;br&gt;    rm &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;rf ~/.nvm/    &lt;br&gt;&lt;br&gt;    php ./vendor/bin/ece&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;tools run scenario/build/generate.xml&lt;br&gt;    php ./vendor/bin/ece&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;tools run scenario/build/transfer.xml&lt;br&gt;  &lt;span class=&quot;token key atrule&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;&lt;br&gt;    php ./vendor/bin/ece-tools run scenario/deploy.xml&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token key atrule&quot;&gt;post_deploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;&lt;br&gt;    php ./vendor/bin/ece-tools run scenario/post-deploy.xml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, it’ll write the &lt;code&gt;app/etc/hyva-themes.json&lt;/code&gt; file and then generate&lt;br&gt;
your Tailwind styles before the main &lt;code&gt;setup:static-content:deploy&lt;/code&gt; runs.&lt;/p&gt;
&lt;p&gt;If you’re running &lt;code&gt;setup:upgrade&lt;/code&gt; at some point in your pipepine before you&lt;br&gt;
generate your tailwind styles then you likely won’t run into this.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Klarna Checkout Won&#39;t Install on Magento 2.4.4</title>
    
    <link href="https://dor.ky/posts/2022/05/klarna-checkout-magento-2.4.4/" rel="alternate" type="text/html"/>
    
    <updated>2022-05-24T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2022/05/klarna-checkout-magento-2.4.4/</id>
    <content type="html">&lt;p&gt;If you’re using the Klarna Checkout package (klarna/m2-checkout) then when you&lt;br&gt;
upgrade to Magento 2.4.4 it won’t install due to a conflict with Monolog&lt;br&gt;
versions. As per a merchant email a short while ago, you need to change over to&lt;br&gt;
the new &lt;code&gt;klarna/m2-checkout&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;You can switch over using:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;composer remove klarna/m2-checkout&lt;br&gt;composer require klarna/m2-klarna&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Re-run a Composer Script After install/create-project</title>
    
    <link href="https://dor.ky/posts/2022/05/composer-re-run-script-after-install-or-create-project/" rel="alternate" type="text/html"/>
    
    <updated>2022-05-23T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2022/05/composer-re-run-script-after-install-or-create-project/</id>
    <content type="html">&lt;p&gt;You can re-run a composer script by using this syntax:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;composer run-script post-create-project-cmd&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Magento 2.4.4 Admin Login Redirect Loop/Not Working</title>
    
    <link href="https://dor.ky/posts/2022/04/magneto-2-4-4-admin-login-not-working-session-redis-redirect/" rel="alternate" type="text/html"/>
    
    <updated>2022-04-25T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2022/04/magneto-2-4-4-admin-login-not-working-session-redis-redirect/</id>
    <content type="html">&lt;p&gt;If you hit a redirect loop in the admin panel after upgrading to 2.4.4 then you&lt;br&gt;
like had the configuration option &lt;code&gt;system/security/max_session_size_admin&lt;/code&gt; set&lt;br&gt;
to &lt;code&gt;0&lt;/code&gt; to fix an issue with 2.4.3 and session size. Setting it to &lt;code&gt;0&lt;/code&gt; in 2.4.4&lt;br&gt;
doesn’t work and causes the session to not get written.&lt;/p&gt;
&lt;p&gt;If you set it to an actual upper limit then it’ll work:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;bin/magento config:set system/security/max_session_size_admin &lt;span class=&quot;token number&quot;&gt;5120000&lt;/span&gt;&lt;br&gt;bin/magento config:set system/security/max_session_size_storefront &lt;span class=&quot;token number&quot;&gt;5120000&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clear the cache and you should be able to login afterwards.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Create Repeating Google Calendar Event for Last Working Day of Month</title>
    
    <link href="https://dor.ky/posts/2022/04/create-google-calendar-event-last-working-day-of-month/" rel="alternate" type="text/html"/>
    
    <updated>2022-04-21T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2022/04/create-google-calendar-event-last-working-day-of-month/</id>
    <content type="html">&lt;p&gt;I think &lt;a href=&quot;https://calendar.google.com/&quot;&gt;Google Calendar&lt;/a&gt; is brilliant however&lt;br&gt;
one type of repeating event it does not support is the last working day of the&lt;br&gt;
month. There is the option to import a custom ICS file though and within the&lt;br&gt;
specification of that file format you can get pretty much close to last working&lt;br&gt;
day (there may be some exceptions where this doesn’t work, such a bank holidays&lt;br&gt;
but it is close enough).&lt;/p&gt;
&lt;p&gt;Create a new file, ie &lt;code&gt;last-working-day.ics&lt;/code&gt; and put this inside it:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;BEGIN:VCALENDAR&lt;br&gt;VERSION:2.0&lt;br&gt;BEGIN:VEVENT&lt;br&gt;RRULE:FREQ&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MONTHLY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;INTERVAL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;WKST&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MO&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BYDAY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MO,TU,WE,TH,FR&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BYSETPOS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;-1&lt;br&gt;SUMMARY:Last working day&lt;br&gt;DTSTART&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;VALUE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;DATE:20220421&lt;br&gt;SEQUENCE:0&lt;br&gt;DESCRIPTION:Repeating last working day event&lt;br&gt;END:VEVENT&lt;br&gt;END:VCALENDAR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save that and then import into &lt;a href=&quot;https://calendar.google.com/&quot;&gt;Google Calendar&lt;/a&gt;&lt;br&gt;
and it’ll create you a new event that repeats on the last working day of the&lt;br&gt;
month. If you need help importing into Google calendar then see &lt;a href=&quot;https://support.google.com/calendar/answer/37118?hl=en&quot;&gt;this page in Google’s help docs&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Create Repeating Google Calendar Event for Last Specific Day of Month</title>
    
    <link href="https://dor.ky/posts/2022/04/create-google-calendar-event-last-specific-day-of-month/" rel="alternate" type="text/html"/>
    
    <updated>2022-04-20T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2022/04/create-google-calendar-event-last-specific-day-of-month/</id>
    <content type="html">&lt;p&gt;I think &lt;a href=&quot;https://calendar.google.com/&quot;&gt;Google Calendar&lt;/a&gt; is brilliant however&lt;br&gt;
one type of repeating event it does not support is the last specific day of the&lt;br&gt;
month. There is the option to import a custom ICS file though and within the&lt;br&gt;
specification of that file format you can do it.&lt;/p&gt;
&lt;p&gt;Create a new file, ie &lt;code&gt;last-wed-of-month.ics&lt;/code&gt; and put this inside it:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;BEGIN:VCALENDAR&lt;br&gt;VERSION:2.0&lt;br&gt;BEGIN:VEVENT&lt;br&gt;RRULE:FREQ&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MONTHLY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;INTERVAL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;WKST&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MO&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BYDAY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;WE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BYSETPOS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;-1&lt;br&gt;SUMMARY:Last Wednesday of Month&lt;br&gt;DTSTART&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;VALUE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;DATE:20220421&lt;br&gt;SEQUENCE:0&lt;br&gt;DESCRIPTION:Last Wednesday of the month&lt;br&gt;END:VEVENT&lt;br&gt;END:VCALENDAR&lt;br&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save that and then import into &lt;a href=&quot;https://calendar.google.com/&quot;&gt;Google Calendar&lt;/a&gt;&lt;br&gt;
and it’ll create you a new event that repeats on the last working day of the&lt;br&gt;
month. If you need help importing into Google calendar then see &lt;a href=&quot;https://support.google.com/calendar/answer/37118?hl=en&quot;&gt;this page in Google’s help docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you need to do a different day to Wednesday, change &lt;code&gt;BYDAY=WE&lt;/code&gt; to match the day you require (one of SU,MO,TU,WE,TH,FR,SA)&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Create Repeating Google Calendar Event for Last Day of Month</title>
    
    <link href="https://dor.ky/posts/2022/04/create-google-calendar-event-last-day-of-month/" rel="alternate" type="text/html"/>
    
    <updated>2022-04-19T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2022/04/create-google-calendar-event-last-day-of-month/</id>
    <content type="html">&lt;p&gt;I think &lt;a href=&quot;https://calendar.google.com/&quot;&gt;Google Calendar&lt;/a&gt; is brilliant however&lt;br&gt;
one type of repeating event it does not support is the last day of the&lt;br&gt;
month. There is the option to import a custom ICS file though and within the&lt;br&gt;
specification of that file format you can do it.&lt;/p&gt;
&lt;p&gt;Create a new file, ie &lt;code&gt;last-day-of-month.ics&lt;/code&gt; and put this inside it:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;BEGIN:VCALENDAR&lt;br&gt;VERSION:2.0&lt;br&gt;BEGIN:VEVENT&lt;br&gt;RRULE:FREQ&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MONTHLY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;INTERVAL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BYSETPOS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;-1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BYDAY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;SU,MO,TU,WE,TH,FR,SA&lt;br&gt;SUMMARY:Last day of the month&lt;br&gt;DTSTART&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;VALUE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;DATE:20220421&lt;br&gt;SEQUENCE:0&lt;br&gt;DESCRIPTION:Last day of the month&lt;br&gt;END:VEVENT&lt;br&gt;END:VCALENDAR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save that and then import into &lt;a href=&quot;https://calendar.google.com/&quot;&gt;Google Calendar&lt;/a&gt;&lt;br&gt;
and it’ll create you a new event that repeats on the last working day of the&lt;br&gt;
month. If you need help importing into Google calendar then see &lt;a href=&quot;https://support.google.com/calendar/answer/37118?hl=en&quot;&gt;this page in Google’s help docs&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Using logrotate as a non-root user</title>
    
    <link href="https://dor.ky/posts/2022/01/use-logrotate-as-a-non-root-user/" rel="alternate" type="text/html"/>
    
    <updated>2022-01-08T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2022/01/use-logrotate-as-a-non-root-user/</id>
    <content type="html">&lt;p&gt;There may be situations when you need to use &lt;a href=&quot;https://linux.die.net/man/8/logrotate&quot;&gt;logrotate&lt;/a&gt; without having root&lt;br&gt;
access to the server that you’re dealing with. In these situations you can&lt;br&gt;
point &lt;code&gt;logrotate&lt;/code&gt; at a state file in your home directory.&lt;/p&gt;
&lt;p&gt;First, create your logrotate configuration file with something like:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;/var/log/messages &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    rotate &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;br&gt;    weekly&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then save to &lt;code&gt;~/logrotate.conf&lt;/code&gt;. Next, touch your state file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;touch ~/.logrotate-state&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;and then you can run logrotate either via SSH or via cron:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/sbin/logrotate —state ~/.logrotate-state ~/.logrotate.conf&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This is useful for providers that don’t give access to &lt;code&gt;logrotate&lt;/code&gt; directly&lt;br&gt;
but the binary is present to use.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Install PHP 7.2 (and 7.1, 7.4 etc) on MacOS Monterey</title>
    
    <link href="https://dor.ky/posts/2022/01/how-to-install-php-72-mac-osx-monterey/" rel="alternate" type="text/html"/>
    
    <updated>2022-01-07T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2022/01/how-to-install-php-72-mac-osx-monterey/</id>
    <content type="html">&lt;p&gt;As PHP older versions have now been deprecated upstream you will encounter&lt;br&gt;
errors when trying to to install via Homebrew. For example, attempting to&lt;br&gt;
install PHP 7.2 will give the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;Error: php@7.2 has been disabled because it is deprecated upstream&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s a tap you can use at &lt;code&gt;shivammathur/php&lt;/code&gt; which has all of the older&lt;br&gt;
versions that are still installable.&lt;/p&gt;
&lt;p&gt;First, tap the repo:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;brew tap shivammathur/php&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then install the PHP version you want:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; shivammathur/php/php@7.2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Give it a few minutes to go off and do it’s thing and you’ll then have the&lt;br&gt;
desired version running locally. I can understand why the PHP deprecated the&lt;br&gt;
older versions but there’s an awful lot of developers out there who will&lt;br&gt;
still need to run and install older versions of PHP due to constraints they&lt;br&gt;
are under.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Easily Create Windows 10/8/7 (or any other OS) Bootable USB Drives</title>
    
    <link href="https://dor.ky/posts/2021/08/creating-bootable-windows-usb-installers/" rel="alternate" type="text/html"/>
    
    <updated>2021-08-09T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2021/08/creating-bootable-windows-usb-installers/</id>
    <content type="html">&lt;p&gt;If you ever need to create a bootable USB installer, the most reliable way that&lt;br&gt;
I’ve found to do so on a Windows machine is using &lt;a href=&quot;https://rufus.ie/en/&quot;&gt;Rufus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It works every single time and I’ve yet to encounter any issues with a drive&lt;br&gt;
created using the tool.&lt;/p&gt;
&lt;p&gt;I last used it to create a Windows 10 bootable drive after their own instructions&lt;br&gt;
didn’t work whereas Rufus worked flawlessly.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Wordpress Docker - How to set memory_limit, max_upload_size and other resource limits</title>
    
    <link href="https://dor.ky/posts/2021/07/wordpress-docker-set-resource-limits--and-memory-limit/" rel="alternate" type="text/html"/>
    
    <updated>2021-07-14T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2021/07/wordpress-docker-set-resource-limits--and-memory-limit/</id>
    <content type="html">&lt;p&gt;To set &lt;code&gt;max_upload_size&lt;/code&gt; and &lt;code&gt;post_max_size&lt;/code&gt; to set in the official docker image, open a bash session and run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;root@f125876a0568:/var/www/html&lt;span class=&quot;token comment&quot;&gt;# echo “php_value upload_max_filesize 256M” &gt;&gt; .htaccess&lt;/span&gt;&lt;br&gt;root@f125876a0568:/var/www/html&lt;span class=&quot;token comment&quot;&gt;# cat .htaccess&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;# snipped&lt;/span&gt;&lt;br&gt;php_value post_max_size 256M&lt;br&gt;php_value upload_max_filesize 256M&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; in the &lt;code&gt;echo&lt;/code&gt; command will append the line to the existing content present.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Stop Yourself Bricking Your Mac - Disable Secure Boot</title>
    
    <link href="https://dor.ky/posts/2021/07/how-to-stop-yourself-bricking-your-mac-disable-secure-boot/" rel="alternate" type="text/html"/>
    
    <updated>2021-07-14T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2021/07/how-to-stop-yourself-bricking-your-mac-disable-secure-boot/</id>
    <content type="html">&lt;p&gt;If you’re lucky to have a newer Mac with a T2 chip in it, at some point you’re likely going to reinstall the OS to freshen things up.&lt;/p&gt;
&lt;p&gt;If “Allow booting from external media” is disabled (see image below) in &lt;a href=&quot;https://support.apple.com/en-gb/HT208198&quot;&gt;Startup Security&lt;/a&gt; and you use Internet Recovery which then fails at any point (past the point of changing disk partitions) - when hen you then reboot your Mac, it’ll be bricked.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://support.apple.com/library/content/dam/edam/applecare/images/en_US/imac/macos-high-sierra-startup-security-utility.png&quot; alt=&quot;Secure boot settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;Internet Recovery can fail for many reasons -  poor internet connection, checksum failure or any other number of things you don’t control.&lt;/p&gt;
&lt;p&gt;The recovery partition will be external media and it’ll refuse to write to the disk in the machine. As expected, other external drives won’t boot either.&lt;/p&gt;
&lt;p&gt;Like me, your Macbook will have to go to for a trip to Apple. The lovely folks at the Genius bar were stumped and the likely remedy at the moment appears to be a logic board replacement.&lt;/p&gt;
&lt;p&gt;To prevent this happening to you, I would &lt;strong&gt;highly recommend&lt;/strong&gt; that you do the following unless you have very good reason not to:&lt;/p&gt;
&lt;p&gt;To allow your Mac to use an external startup disk:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open Startup Security Utility.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select “Allow booting from external media”.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There instructions are present on Apples site linked above.&lt;/p&gt;
&lt;p&gt;Security is useful, everyone would agree but the default for this surely has to be off/allowing external media. At no point in having this Mac did I set that (I didn’t even know the option existed).&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Magento 2 - How to delete all special prices</title>
    
    <link href="https://dor.ky/posts/2021/05/magento-2-how-to-delete-all-special-prices/" rel="alternate" type="text/html"/>
    
    <updated>2021-05-18T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2021/05/magento-2-how-to-delete-all-special-prices/</id>
    <content type="html">&lt;p&gt;If you ever need to remove all special/sale prices from a Magento 2 installation, you can use the following SQL to do so.&lt;/p&gt;
&lt;p&gt;First step, back up your databases if you haven’t already. Specifically the &lt;code&gt;catalog_product_entity_decimal&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;Then run the following SQL:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; catalog_product_entity_decimal&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; attribute_id &lt;span class=&quot;token operator&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; attribute_id &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; eav_attribute &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; attribute_code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ‘special_price’&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to see what it’s going to delete beforehand, run this query instead:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; catalog_product_entity_decimal&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; attribute_id &lt;span class=&quot;token operator&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; attribute_id &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; eav_attribute &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; attribute_code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ‘special_price’&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After it has completed, run &lt;code&gt;bin/magento indexer:reindex&lt;/code&gt; to reindex the changed prices.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>macOS Big Sur - Installing pip for Python</title>
    
    <link href="https://dor.ky/posts/2020/11/macos-big-sur-install-python-pip/" rel="alternate" type="text/html"/>
    
    <updated>2020-11-15T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2020/11/macos-big-sur-install-python-pip/</id>
    <content type="html">&lt;p&gt;The new version of macOS doesn’t appear to have &lt;code&gt;pip&lt;/code&gt; installed by default, you can install it by running this command in a Terminal window:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; easy_install &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; pip&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: Make sure that you have version 12.2 of Xcode installed and that in Xcode -&amp;gt; Preferences -&amp;gt; Locations -&amp;gt; Command Line Tools is set to Xcode 12.2 too.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>A quick way to truncate files on Mac and Linux systems</title>
    
    <link href="https://dor.ky/posts/2020/10/quickly-truncate-a-file/" rel="alternate" type="text/html"/>
    
    <updated>2020-10-29T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2020/10/quickly-truncate-a-file/</id>
    <content type="html">&lt;p&gt;A short-hand method of truncating files is by using this syntax:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /path/to/filename.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once it has ran then the files content will be removed and the file itself left in place.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Show user groups on Linux</title>
    
    <link href="https://dor.ky/posts/2020/08/show-user-groups-on-linux/" rel="alternate" type="text/html"/>
    
    <updated>2020-08-29T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2020/08/show-user-groups-on-linux/</id>
    <content type="html">&lt;p&gt;On most standard Linux operating systems you can view the current users’&lt;br&gt;
group membership with:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;id&lt;/span&gt; -nG&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or if you’re currently logged in as &lt;code&gt;root&lt;/code&gt; then you can just tag the user&lt;br&gt;
that you want to view on the end of the command. For example, if I’m logged in&lt;br&gt;
as &lt;code&gt;root&lt;/code&gt; and want to see the groups that &lt;code&gt;john&lt;/code&gt; is a member of:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;id&lt;/span&gt; -nG john&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which will then output:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;root@mimas:~&lt;span class=&quot;token comment&quot;&gt;# id -nG john&lt;/span&gt;&lt;br&gt;john docker&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>A neat app for team safety checkins and announcements</title>
    
    <link href="https://dor.ky/posts/2020/07/neat-app-for-safety-checkins/" rel="alternate" type="text/html"/>
    
    <updated>2020-07-31T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2020/07/neat-app-for-safety-checkins/</id>
    <content type="html">&lt;div class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Clever little iOS app for businesses/teams called Mustr. &lt;br&gt;&lt;br&gt;It can broadcast critical/urgent messages to your team and take roll calls to make sure everyone’s healthy, safe and secure.&lt;br&gt;&lt;br&gt;🔗 &lt;a href=&quot;https://t.co/HdOah1fKHa&quot;&gt;https://t.co/HdOah1fKHa&lt;/a&gt;&lt;a href=&quot;https://twitter.com/hashtag/ios?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#ios&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/app?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#app&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/teams?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#teams&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/remotework?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#remotework&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/remote?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#remote&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/safety?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#safety&lt;/a&gt;&lt;/p&gt;&amp;mdash; Scott (@ssxio) &lt;a href=&quot;https://twitter.com/ssxio/status/1288967925039345664?ref_src=twsrc%5Etfw&quot;&gt;July 30, 2020&lt;/a&gt;&lt;/div&gt; 
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Keeping Your Privacy: How to Set-up Your Own VPN Using Cloud Providers</title>
    
    <link href="https://dor.ky/posts/2020/06/how-to-setup-your-own-vpn-using-cloud-provider/" rel="alternate" type="text/html"/>
    
    <updated>2020-06-14T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2020/06/how-to-setup-your-own-vpn-using-cloud-provider/</id>
    <content type="html">&lt;p&gt;This post is part of a series called &lt;a href=&quot;https://dor.ky/posts/2020/06/introducing-a-series-keeping-your-privacy-while-protesting/&quot;&gt;“Keeping Your Privacy”&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;There are a hundred and one reasons to run your own VPN - the biggest and most commonly referenced is privacy. You can control your own privacy when using public networks or public wifi for example. If you’re connecting via your own VPN service then you’re a lot more hidden.&lt;/p&gt;
&lt;p&gt;In the current climate of protests you would be able to protect your communications over 4G mobile data networks if you had your own VPN.&lt;/p&gt;
&lt;h3 id=&quot;our-vpn-choice&quot;&gt;Our VPN Choice&lt;/h3&gt;
&lt;p&gt;We’re going to use &lt;a href=&quot;https://github.com/StreisandEffect/streisand&quot;&gt;Streisand&lt;/a&gt; for our VPN. As we can read from their Github repository:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Streisand sets up a new server running your choice of WireGuard, OpenConnect, OpenSSH, OpenVPN, Shadowsocks, sslh, Stunnel, or a Tor bridge. It also generates custom instructions for all of these services. At the end of the run you are given an HTML file with instructions that can be shared with friends, family members, and fellow activists.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, out of the box we get OpenVPN setup and configured, along with socks proxies and some other neat features with minimal configuration. The actual reason I selected Streisand is because I wanted something OpenVPN compatible and once the server has finished setting itself up - it writes a folder full of documentation for each service that explains how to configure your devices and start using the services offered&lt;/p&gt;
&lt;h3 id=&quot;select-a-cloud-provider&quot;&gt;Select a Cloud Provider&lt;/h3&gt;
&lt;p&gt;We’re going to need a cloud provider to run your VPN within. My advice is the same for when you’re running any kind of server on other peoples hardware - pick a company you trust and feel comfortable with. Over the years I’ve launched projects both small and large. Some clients picked AWS and some picked &lt;a href=&quot;https://go.ssx.io/signup-digitalocean&quot;&gt;DigitalOcean&lt;/a&gt;. If you haven’t got an account set up, you can use one of these referral links to get free credit (and I’ll get a small amount of credit too):&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://go.ssx.io/signup-digitalocean&quot;&gt;DigitalOcean&lt;/a&gt;&lt;br&gt;
Linode&lt;br&gt;
Vultr&lt;br&gt;
AWS LightSail&lt;/p&gt;
&lt;p&gt;Next, the process for creating a new server varies between platform. We’re going to create a new Ubuntu 16.10 server (due to its great compatibility with Streisand).&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/430497456&quot; width=&quot;640&quot; height=&quot;480&quot; frameborder=&quot;0&quot; allow=&quot;autoplay; fullscreen&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Linode, AWS Lightsail and Vultr videos will be added shortly.&lt;/p&gt;
&lt;p&gt;After the server creation is completed and you’ve got a running Ubuntu 16.10 server, copy the IP address and we can move to the installation stage.&lt;/p&gt;
&lt;h3 id=&quot;pick-your-subdomain-and-configure-dns&quot;&gt;Pick Your Subdomain and Configure DNS&lt;/h3&gt;
&lt;p&gt;You’re going to need a fully set up DNS record for your new VPN server, if you own &lt;code&gt;bob.com&lt;/code&gt;, then &lt;code&gt;vpn.bob.com&lt;/code&gt; wouldn’t be a bad choice. You’ll need this during set-up of Streisand so make sure your DNS A record exists and &lt;strong&gt;points at your new servers IP address&lt;/strong&gt; otherwise installation will fail and SSL certificates won’t be issued properly.&lt;/p&gt;
&lt;h3 id=&quot;streisand-installation&quot;&gt;Streisand Installation&lt;/h3&gt;
&lt;p&gt;Follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;SSH in as root to your server &lt;code&gt;ssh root@your-server-ip&lt;/code&gt; (or via the DNS name for your box as you should have set that up already)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;code&gt;apt-get install git python3 python3-venv&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Clone the Streisand repo: &lt;code&gt;git clone https://github.com/StreisandEffect/streisand.git &amp;amp;&amp;amp; cd streisand&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;code&gt;./util/venv-dependencies.sh ./venv&lt;/code&gt; and it’ll report anything more you need to do. Follow any instructions it gives you&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;code&gt;source ./venv/bin/activate&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;run  &lt;code&gt;./streisand&lt;/code&gt; and follow prompts. Defaults are fine to all answers.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;device-configuration&quot;&gt;Device Configuration&lt;/h3&gt;
&lt;p&gt;If you SFTP to your new server, checkout the directory that you cloned Streisand into and there will be a directory called &lt;code&gt;generated-docs&lt;/code&gt; with configuration information and instructions. Supports Mac OS, iOS, Android, Windows and more.&lt;/p&gt;
&lt;h3 id=&quot;follow-on%3A&quot;&gt;Follow on:&lt;/h3&gt;
&lt;p&gt;It’d be wise to set the reverse-dns entry for your servers IP address and also have a look around for other VPN setup packages - I’ve heard good things about &lt;a href=&quot;https://github.com/trailofbits/algo&quot;&gt;Algo&lt;/a&gt; along with Streisand.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Keeping Your Privacy: Face Blurring &amp; EXIF Data</title>
    
    <link href="https://dor.ky/posts/2020/06/keeping-your-privacy-while-protesting/" rel="alternate" type="text/html"/>
    
    <updated>2020-06-11T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2020/06/keeping-your-privacy-while-protesting/</id>
    <content type="html">&lt;p&gt;This post is part of a series called &lt;a href=&quot;https://dor.ky/posts/2020/06/introducing-a-series-keeping-your-privacy-while-protesting/&quot;&gt;“Keeping Your Privacy”&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;It has been truly remarkable to see the &lt;a href=&quot;https://en.wikipedia.org/wiki/George_Floyd_protests&quot;&gt;protests around the world&lt;/a&gt; in the last two weeks. A message seems to be spreading and getting through to politicians and those in power at least seem to acknowledge that something has to change going forward.&lt;/p&gt;
&lt;p&gt;The liability in the White House hasn’t exactly helped matters state side but with a white supremacist in the hot seat it’s not exactly a surprise. You don’t even have to think too far back to some of the early &lt;a href=&quot;https://www.washingtonpost.com/politics/2019/04/25/meet-trump-charlottesville-truthers/&quot;&gt;remarks on Charlottesville&lt;/a&gt; for an indication of who Trump really is. Anyhow, I digress as that isn’t the topic at hand.&lt;/p&gt;
&lt;p&gt;There are a few things that people protesting need to remember from my experience and I’ve seen countless others say similar.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep your face covered, once these protests are over I have zero doubt that the police will try and start to identify people taking part.&lt;/li&gt;
&lt;li&gt;The same goes for those with microphones/amplifiers. You’ll be even more of a target for being more active in the protest&lt;/li&gt;
&lt;li&gt;By all means, take and share photos, videos and whatever else you want to but crucially cover faces. Traditionally people would blur these but I’m not so sure that is a good idea any more which I’ll elaborate more on below.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;blurred-lines&quot;&gt;Blurred Lines&lt;/h3&gt;
&lt;p&gt;Over the years I’ve seen plenty of people blur photos and videos of people taking part in protests to hide their identity. After recently researching more into it and finding the work of &lt;a href=&quot;http://yuzhikov.com/articles/BlurredImagesRestoration1.htm&quot;&gt;Vladimir Yuzhikov&lt;/a&gt; - I would highly recommend covering with a big block of colour to hide peoples identities and &lt;em&gt;no longing use blur as an effective privacy tool&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;What I also feel strongly about is that while Vladimir was able to achieve these fantastic results with modest software and knowledge - I’m sure that law enforcement staff have a tool which will de-blur a lot quicker and provide immediate results.&lt;/p&gt;
&lt;h3 id=&quot;be-wary-of&quot;&gt;Be Wary of&lt;/h3&gt;
&lt;p&gt;One last thought here is that I’ve seen a number of people on Twitter offering to help ‘cover up’ protesters faces and protect their privacy for you. While I’m sure most of these offers are genuine I couldn’t help the uneasy feeling I had - I’d bet that some of those offering help were likely police phishing around for photos and videos from the protests as they’re now &lt;a href=&quot;https://www.latimes.com/california/story/2020-06-02/not-so-fast-lapd-other-agencies-collect-unrest-footage-as-evidence-for-future-arrests&quot;&gt;collecting evidence&lt;/a&gt; which will likely lead to arrests in future.&lt;/p&gt;
&lt;p&gt;In short, I’d stick with the same rule I have for sending money to people online - don’t do it unless you know them in person.&lt;/p&gt;
&lt;h3 id=&quot;one-last-thing---exif&quot;&gt;One Last Thing - EXIF&lt;/h3&gt;
&lt;p&gt;When you take a photo, your camera embeds certain data inside the photo file. This contains things like light levels, camera configuration and sometimes the physical location the photograph was taken in (some video recording hardware does this in a slightly different way - Go Pro for example).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before you share your photos/videos online - I’d &lt;em&gt;highly, highly&lt;/em&gt; recommend you strip the &lt;a href=&quot;https://en.wikipedia.org/wiki/Exif&quot;&gt;EXIF&lt;/a&gt; data from your files - at a minimum remove the location data.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For an iPhone, &lt;a href=&quot;https://www.imore.com/how-remove-exif-data-your-photos-iphone&quot;&gt;follow this iMore guide&lt;/a&gt;. Also this is easy on an iOS or Mac device, for other platforms I can imagine this being difficult to do.&lt;/p&gt;
&lt;p&gt;Android has &lt;a href=&quot;https://play.google.com/store/apps/details?id=apps.syrupy.metadatacleaner&amp;amp;hl=en_GB&quot;&gt;Metadata Cleaner&lt;/a&gt; but I’ve not personally tested that. For those on Windows, give &lt;a href=&quot;http://www.exifpurge.com/&quot;&gt;ExifPurge&lt;/a&gt; a try. Linux users can use the brilliant &lt;a href=&quot;https://www.linux-magazine.com/Online/Blogs/Productivity-Sauce/Remove-EXIF-Metadata-from-Photos-with-exiftool&quot;&gt;exiftool&lt;/a&gt; to handle their images.&lt;/p&gt;
&lt;p&gt;If you’re on a different platform then I’d suggest you try Googling for &#39;Remove Exif data from &lt;camera name=&quot;&quot;&gt; on &lt;computer type=&quot;&quot;&gt;’ and see what you find.&lt;/computer&gt;&lt;/camera&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Introducing a Series: Keeping Your Privacy</title>
    
    <link href="https://dor.ky/posts/2020/06/introducing-a-series-keeping-your-privacy-while-protesting/" rel="alternate" type="text/html"/>
    
    <updated>2020-06-10T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2020/06/introducing-a-series-keeping-your-privacy-while-protesting/</id>
    <content type="html">&lt;p&gt;Everyone is aware that privacy online is an important topic. It becomes even more important when you apply the context of the current protests and people needing to protect their identity.&lt;/p&gt;
&lt;p&gt;I’m lucky that I’ve worked as a professional software developer for a long time and know how to configure, run and operate lots of different services. When the protests broke out worldwide I felt like I should use my knowledge to share with others how to protect themselves.&lt;/p&gt;
&lt;p&gt;There’s a famous Desmond Tutu quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“If you are neutral in situations of injustice, you have chosen the side of the oppressor. If an elephant has its foot on the tail of a mouse, and you say that you are neutral, the mouse will not appreciate your neutrality.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With doing a small thing to share knowledge with others, if that only helps one other person then it’s been worthwhile.&lt;/p&gt;
&lt;p&gt;This page will act as the overview for this series and it starts with an explanation of blurring faces from your media and removing &lt;a href=&quot;https://en.wikipedia.org/wiki/Exif&quot;&gt;EXIF&lt;/a&gt; data.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dor.ky/posts/2020/06/keeping-your-privacy-while-protesting/&quot;&gt;Keeping Your Privacy: Face Blurring &amp;amp; EXIF Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Keeping Your Privacy: How to Set-up Your Own VPN Using Cloud Providers &lt;strong&gt;[Coming Soon]&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Install and Configure Docker on Ubuntu 20.04</title>
    
    <link href="https://dor.ky/posts/2020/06/how-to-install-and-configure-docker-on-ubuntu-20/" rel="alternate" type="text/html"/>
    
    <updated>2020-06-09T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2020/06/how-to-install-and-configure-docker-on-ubuntu-20/</id>
    <content type="html">&lt;p&gt;Create a non-root user to run your docker containers under:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;adduser steve&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, update the apt sources and install Docker:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; docker.io&lt;br&gt;systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; —now docker&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, add our new user to the docker user group so they can interact with the service:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;usermod&lt;/span&gt; -aG docker steve&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and finally, we’ll switch over to that user using &lt;code&gt;su&lt;/code&gt; and confirm we can run a simple container:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;su&lt;/span&gt; steve&lt;br&gt;docker run hello-world&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’ll print out the Docker welcome message, confirming that each step of the process succeeded. If you want to try something a little more interesting, you can boot an Ubuntu container with:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run -it ubuntu &lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-it&lt;/code&gt; tells Docker that you want to run this interactively and to assign a tty to you&lt;/p&gt;
&lt;p&gt;Other than that, you can run pretty normal things within your Ubuntu container but keep in mine any changes you make or configuration you do won’t be persisted.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Configure and Use Hardware Yubikey with Mac OS SSH</title>
    
    <link href="https://dor.ky/posts/2020/05/how-to-configure-and-use-hardware-yubikey-with-mac-os-ssh/" rel="alternate" type="text/html"/>
    
    <updated>2020-05-22T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2020/05/how-to-configure-and-use-hardware-yubikey-with-mac-os-ssh/</id>
    <content type="html">&lt;p&gt;Due to recent updates to OpenSSH there is now a much simpler and easier way to use hardware tokens for SSH access.&lt;/p&gt;
&lt;p&gt;Start by inserting your Yubikey into your Mac.&lt;/p&gt;
&lt;p&gt;Create a new key &lt;code&gt;ecdsa-sk&lt;/code&gt; which will reside on your machine but require your hardware token:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh-keygen -t ecdsa-sk -f ~/.ssh/id_ecdsa_sk -C “user@site.co”&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’ll ask you to enter a password to protect your key, then if touch compatible you’ll need to press the light when asked.&lt;/p&gt;
&lt;p&gt;Copy the contents of &lt;code&gt;~/.ssh/id_ecdsa_sk.pub&lt;/code&gt; to the &lt;code&gt;.ssh/authorized_keys&lt;/code&gt; file on your remote server and then you’re ready to test the connection works, login using your new identity:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ssh&lt;/span&gt; -i ~/.ssh/id_ecdsa_sk user@server.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll then be protected for your key password, then prompted to authorise the connection request by touching your hardware key:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://static.dor.ky/blog/2020/05/ssh_setup.png&quot; alt=&quot;SSH Setup&quot; title=&quot;SSH Setup&quot;&gt;&lt;/p&gt;
&lt;p&gt;It makes it easier to store the identity file in your &lt;code&gt;.ssh/config&lt;/code&gt; file so you don’t have to type it out each time, use a configuration like this:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;Host servername&lt;br&gt;     User ssh-username&lt;br&gt;     Hostname servername.server.tld&lt;br&gt;     Port &lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt;&lt;br&gt;     IdentityFile ~/.ssh/id_ecdsa_sk&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This now means that you can just type &lt;code&gt;ssh servername&lt;/code&gt; and it’ll automatically use the right user, hostname, port and key.&lt;/p&gt;
&lt;h3 id=&quot;%E2%80%A6and-without-the-hardware-key%3F&quot;&gt;…and without the hardware key?&lt;/h3&gt;
&lt;p&gt;If you don’t have your hardware key plugged in to you machine when you try to connect, then you’ll get this error:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://static.dor.ky/blog/2020/05/ssh_no_key.png&quot; alt=&quot;SSH with no key&quot; title=&quot;SSH with no key&quot;&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Using Additional Configuration Files with Laravel &amp; Lumen</title>
    
    <link href="https://dor.ky/posts/2020/05/using-additional-configuration-files-with-laravel-and-lumen/" rel="alternate" type="text/html"/>
    
    <updated>2020-05-21T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2020/05/using-additional-configuration-files-with-laravel-and-lumen/</id>
    <content type="html">&lt;p&gt;If you’ve got a growing Lumen application or perhaps you just want clear separation of configuration - it can be beneficial to add more configuration files to the &lt;code&gt;config/&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;These files are pretty simple in nature, if I was creating one to configure settings for users, I could create a file called &lt;code&gt;config/user.php&lt;/code&gt; containing:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;prefix&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;user_&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;table&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;users&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;permissions&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;		CanPost&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;		CanDelete&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;		CanLogin&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Laravel will load this file when accessed by default but Lumen on the other hand doesn’t. To get access to it via the config() helper, you’ll need to add the following line:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$app&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;‘user’&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To your  &lt;code&gt;bootstrap/app.php&lt;/code&gt;file which will tell Lumen that there is an additional configuration file to use. After this has been done, you’ll be able to use the &lt;code&gt;config()&lt;/code&gt; helper like normal. For example, to get the permissions we configured above:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$permissions&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;‘user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;permissions&#39;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can read more about &lt;a href=&quot;https://laravel.com/docs/7.x/configuration&quot;&gt;configuration files on the Laravel website&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Git reflog can help you restore lost work</title>
    
    <link href="https://dor.ky/posts/2019/10/git-reflog-can-help-you-restore-lost-work/" rel="alternate" type="text/html"/>
    
    <updated>2019-10-26T18:38:00-00:00</updated>
    <id>https://dor.ky/posts/2019/10/git-reflog-can-help-you-restore-lost-work/</id>
    <content type="html">&lt;p&gt;A lot of the software developers I’ve interacted with hold a basic working&lt;br&gt;
knowledge of git which I’ve always found surprising as a lot of pieces&lt;br&gt;
sound a lot scarier to hear than they are to use. An example of this would&lt;br&gt;
be git rebasing - people immediately seem to worry about this even though at&lt;br&gt;
the end of the day its a relatively simple concept - you have a stack of&lt;br&gt;
commits and you want to trim them down.&lt;/p&gt;
&lt;p&gt;Another one is the git reflog - there are times in your career when you&lt;br&gt;
may need to use the reflog to rescue yourself.&lt;/p&gt;
&lt;p&gt;In an existing profile, type &lt;code&gt;git reflog&lt;/code&gt; and you’ll be presented with a&lt;br&gt;
view similar to this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/posts/git-reflog.png&quot; alt=&quot;git reflog&quot; title=&quot;git reflog&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you want to make it a little easier to work out when each change was&lt;br&gt;
made, then tag on &lt;code&gt;--date=iso&lt;/code&gt; and run that instead:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git reflog --date=iso&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;and you’ll get the same output as above but with time and dates:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/posts/git-reflog-with-datetime.png&quot; alt=&quot;git reflog with date/time&quot; title=&quot;git reflog with date/time&quot;&gt;&lt;/p&gt;
&lt;p&gt;What this shows you is all the activity that has taken place in the&lt;br&gt;
repository. It’ll show you merges, rebases, pulls, commits and more. It&lt;br&gt;
will also contain all changes in your repo that were not&lt;br&gt;
committed/staged as well - meaning you can recover accidental deletions&lt;br&gt;
and rectify other mistakes. For each of the HEAD@{N} lines, you can&lt;br&gt;
check each of those lines out, by using:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git checkout HEAD@{9}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you want to &lt;em&gt;really&lt;/em&gt; see everything that has happened to your&lt;br&gt;
repository then you can actually pass an extra flag to &lt;code&gt;git reflog&lt;/code&gt;&lt;br&gt;
like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git reflog show --all&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You can find more information and some extra reading at the&lt;br&gt;
following sites:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-reflog&quot;&gt;git-scm.com/docs/git-reflog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.atlassian.com/git/tutorials/rewriting-history/git-reflog&quot;&gt;atlassian.com/git/tutorials/rewriting-history/git-reflog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://coderwall.com/p/ygjvsa/git-reflog-should-be-your-friend&quot;&gt;coderwall.com/p/ygjvsa/git-reflog-should-be-your-friend&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve hope you found this post informative enough to be confident in&lt;br&gt;
exploring everything git can offer you.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How-to set downloaded filename for S3 pre-signed URLs in PHP</title>
    
    <link href="https://dor.ky/posts/2019/10/settings-filename-for-s3-pre-signed-urls/" rel="alternate" type="text/html"/>
    
    <updated>2019-10-01T20:54:00-00:00</updated>
    <id>https://dor.ky/posts/2019/10/settings-filename-for-s3-pre-signed-urls/</id>
    <content type="html">&lt;p&gt;If you use S3 to store files then the chances are at some point you’ll be&lt;br&gt;
letting users download these files themselves. If you don’t want to fetch the&lt;br&gt;
file yourself and you want to send the user directly to S3 to download it - you&lt;br&gt;
can do this securely using pre-signed URLs. In short, a temporary URL is&lt;br&gt;
generated to allow the user access to the file and it has a timed expiry.&lt;/p&gt;
&lt;p&gt;If you’re normalising and storing your files with something like this structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;file_id     file_name       file_type       aws_path

1022        sample          pdf             uploaded/documents/1022.pdf
1023        budget          xlsx            uploaded/documents/1023.xlsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you were sending the user to S3 directly, they’d be given a file to download&lt;br&gt;
of 1022.pdf - hardly an ideal filename. You can modifying the filename for the&lt;br&gt;
user when you create the pre-signed URL, like so:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$s3Client&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Aws&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;S3&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;S3Client&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;profile&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;default&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;region&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;us-east-2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;version&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;2006-03-01&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token variable&quot;&gt;$cmd&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$s3Client&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;GetObject&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;Bucket&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;my-bucket&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;Key&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;testKey&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;ResponseContentDisposition&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;attachment; filename=sample.pdf&#39;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$s3Client&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createPresignedRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$cmd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;+20 minutes&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token double-quoted-string string&quot;&gt;&quot;Location: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you then forward the user to the give URL they will be given a download&lt;br&gt;
with the correct file name.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Zip and Encrypt a file on a Mac</title>
    
    <link href="https://dor.ky/posts/2019/05/how-to-zip-and-encrypt-a-file-on-a-mac/" rel="alternate" type="text/html"/>
    
    <updated>2019-05-11T18:35:00-00:00</updated>
    <id>https://dor.ky/posts/2019/05/how-to-zip-and-encrypt-a-file-on-a-mac/</id>
    <content type="html">&lt;p&gt;I’d recently seen a few people recommending app store apps to handle zipping and encrypting files/directories on a Mac.&lt;/p&gt;
&lt;p&gt;Open up a Terminal session and locate the directory you need and run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;zip&lt;/span&gt; -er secret-files.zip directory-of-files/things.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll then be prompted to enter the password and confirm it.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Strong Customer Authentication (SCA)</title>
    
    <link href="https://dor.ky/posts/2019/04/strong-customer-authentication-(SCA)/" rel="alternate" type="text/html"/>
    
    <updated>2019-04-10T20:22:00-00:00</updated>
    <id>https://dor.ky/posts/2019/04/strong-customer-authentication-(SCA)/</id>
    <content type="html">&lt;p&gt;Later this year on September 14th a new European payment law will come into use. For consumers its a brilliant step forward. Essentially the new law requires two-factor auth when checking out which should cut down on card fraud.&lt;/p&gt;
&lt;p&gt;If you’re a Stripe user, all you’ll need to do is implement 3D Secure 2. This will cover your requirements for the new law. I asked Stripe on Twitter to confirm this (which they helpfully did):&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Yep—you&amp;#39;ll want to confirm that your integration is one that supports 3D Secure 2. &lt;a href=&quot;https://t.co/bnFH0XmU3a&quot;&gt;https://t.co/bnFH0XmU3a&lt;/a&gt; can help get you started on this!&lt;/p&gt;&amp;mdash; Stripe (@stripe) &lt;a href=&quot;https://twitter.com/stripe/status/1115683474575433728?ref_src=twsrc%5Etfw&quot;&gt;April 9, 2019&lt;/a&gt;&lt;/blockquote&gt; &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;I’ll be sticking with Stripe going forward, purely because they will handle most of this for me. You can read more information about what’s needed over on the Stripe docs for &lt;a href=&quot;https://stripe.com/en-GB/guides/strong-customer-authentication&quot;&gt;Strong Customer Authentication&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h3&gt;
&lt;p&gt;You can find out more information about SCA within these pages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stripe.com/en-GB/guides/strong-customer-authentication&quot;&gt;https://stripe.com/en-GB/guides/strong-customer-authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jpmorgan.com/europe/merchant-services/strong-customer-authentication&quot;&gt;https://www.jpmorgan.com/europe/merchant-services/strong-customer-authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.barclaycard.co.uk/business/news-and-insights/guide-to-strong-customer-authentication&quot;&gt;https://www.barclaycard.co.uk/business/news-and-insights/guide-to-strong-customer-authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32018R0389&quot;&gt;https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32018R0389&lt;/a&gt;](* &lt;a href=&quot;https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32018R0389&quot;&gt;https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32018R0389&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eba.europa.eu/-/eba-provides-clarity-to-market-participants-for-the-implementation-of-the-technical-standards-on-strong-customer-authentication-and-common-and-secure-&quot;&gt;https://eba.europa.eu/-/eba-provides-clarity-to-market-participants-for-the-implementation-of-the-technical-standards-on-strong-customer-authentication-and-common-and-secure-&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eba.europa.eu/regulation-and-policy/payment-services-and-electronic-money/regulatory-technical-standards-on-strong-customer-authentication-and-secure-communication-under-psd2&quot;&gt;https://eba.europa.eu/regulation-and-policy/payment-services-and-electronic-money/regulatory-technical-standards-on-strong-customer-authentication-and-secure-communication-under-psd2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.visaeurope.com/about-us/policy-and-regulation/&quot;&gt;http://www.visaeurope.com/about-us/policy-and-regulation/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.fca.org.uk/firms/revised-payment-services-directive-psd2&quot;&gt;https://www.fca.org.uk/firms/revised-payment-services-directive-psd2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gemalto.com/financial/ebanking/psd2&quot;&gt;https://www.gemalto.com/financial/ebanking/psd2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.braintreepayments.com/blog/understanding-and-preparing-for-psd2-strong-customer-authentication/&quot;&gt;https://www.braintreepayments.com/blog/understanding-and-preparing-for-psd2-strong-customer-authentication/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.adyen.com/blog/psd2-understanding-strong-customer-authentication&quot;&gt;https://www.adyen.com/blog/psd2-understanding-strong-customer-authentication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  
  <entry>
    <title>PHP 5.6 Vagrant Box for Legacy Projects</title>
    
    <link href="https://dor.ky/posts/2019/03/php56-vagrant-box-for-legacy-projects/" rel="alternate" type="text/html"/>
    
    <updated>2019-03-14T19:30:00-00:00</updated>
    <id>https://dor.ky/posts/2019/03/php56-vagrant-box-for-legacy-projects/</id>
    <content type="html">&lt;p&gt;I’ve never one to say there shouldn’t be any legacy projects.  I’m sure plenty of&lt;br&gt;
developers who would like to change the definition of a legacy project to suit&lt;br&gt;
this weeks best practices but in all honestly there are legacy applications out&lt;br&gt;
there generating hundreds and thousands of pounds for many companies. That in&lt;br&gt;
itself should be respected.&lt;/p&gt;
&lt;p&gt;Legacy has become a dirty word somehow. It shouldn’t be. We all have legacy&lt;br&gt;
projects to work on.&lt;/p&gt;
&lt;p&gt;Joe’s latest project - &lt;a href=&quot;https://www.joeferguson.me/announcing-homestead-fifty-six/&quot;&gt;Homestead Fifty Six&lt;/a&gt;&lt;br&gt;
has various price points to support the project. Joe has structured these in a&lt;br&gt;
very fair manner I believe. For a project which will clearly save developers a&lt;br&gt;
lot of time (I’ve recently had to create two Vagrant PHP5.6 boxes and each easily&lt;br&gt;
took over a few hours).&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Firefox Send</title>
    
    <link href="https://dor.ky/posts/2019/03/firefox-send/" rel="alternate" type="text/html"/>
    
    <updated>2019-03-13T21:10:00-00:00</updated>
    <id>https://dor.ky/posts/2019/03/firefox-send/</id>
    <content type="html">&lt;p&gt;Mozilla unveiled a new product this week called &lt;a href=&quot;https://send.firefox.com/&quot;&gt;Firefox Send&lt;/a&gt;. It allows you to securely transfer files to friends, family and colleagues and anyone else around the world in a few clicks.&lt;/p&gt;
&lt;p&gt;I used to use &lt;a href=&quot;https://transfer.sh/&quot;&gt;transfer.sh&lt;/a&gt; to do this on a self-hosted instance but going forward I’ll be using this.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Nginx acquired by F5 Networks</title>
    
    <link href="https://dor.ky/posts/2019/03/nginx-acquired/" rel="alternate" type="text/html"/>
    
    <updated>2019-03-12T20:02:00-00:00</updated>
    <id>https://dor.ky/posts/2019/03/nginx-acquired/</id>
    <content type="html">&lt;p&gt;A piece of news that seems to have been under the radar this week is that &lt;a href=&quot;https://www.f5.com/&quot;&gt;F5&lt;/a&gt; have acquired &lt;a href=&quot;https://www.nginx.com/blog/nginx-joins-f5/&quot;&gt;nginx&lt;/a&gt;. I’ve been using nginx for a long time now along with countless others in the developer/devops community - I’m hoping that this doesn’t mean too many changes going forward to what is an excellent product.&lt;/p&gt;
&lt;p&gt;You can read the &lt;a href=&quot;https://www.nginx.com/blog/nginx-joins-f5/&quot;&gt;press announcement here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Automatically Start Laravel Horizon with Vessel</title>
    
    <link href="https://dor.ky/posts/2019/02/automatically-starting-laravel-horizon-with-vessel/" rel="alternate" type="text/html"/>
    
    <updated>2019-02-15T20:50:00-00:00</updated>
    <id>https://dor.ky/posts/2019/02/automatically-starting-laravel-horizon-with-vessel/</id>
    <content type="html">&lt;p&gt;If you’re a more advanced Laravel user there is a fair chance you will be using&lt;br&gt;
&lt;a href=&quot;https://laravel.com/docs/5.7/horizon&quot;&gt;Laravel Horizon&lt;/a&gt; to run your queue&lt;br&gt;
configurations. If you’re using the excellent Vessel via &lt;a href=&quot;https://github.com/shipping-docker/vessel&quot;&gt;Shipping Docker&lt;/a&gt;/&lt;a href=&quot;https://serversforhackers.com/&quot;&gt;Chris Fidao&lt;/a&gt;&lt;br&gt;
then it can be annoying to have to drop into a container and manually start&lt;br&gt;
Horizon.&lt;/p&gt;
&lt;p&gt;Create a new file in your project named &lt;code&gt;start_horizon.sh&lt;/code&gt; in the &lt;code&gt;docker/app&lt;/code&gt;&lt;br&gt;
directory, enter the contents of the file which should be:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;br&gt;/usr/bin/php /var/www/html/artisan horizon&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save that file, and &lt;code&gt;chmod +x start_horizon.sh&lt;/code&gt;. Next, open the file&lt;br&gt;
&lt;code&gt;supervisord.conf&lt;/code&gt; in the same directory and add:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;program:horizon&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/var/www/html/docker/app/start_horizon.sh&quot;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/var/www/html/&lt;br&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;stdout_logfile&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/dev/stdout&lt;br&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;stdout_logfile_maxbytes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;stderr_logfile&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/dev/stderr&lt;br&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;stderr_logfile_maxbytes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;near the bottom of the file. Save the file and then rebuild your Vessel image,&lt;br&gt;
using &lt;code&gt;./vessel build&lt;/code&gt;. After you restart your project with &lt;code&gt;vessel up&lt;/code&gt; you&lt;br&gt;
will have a running Horizon instance that you no longer manually need to start.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel Nova - Trimmed Field Pattern</title>
    
    <link href="https://dor.ky/posts/2019/02/laravel-nova-trim-fields-pattern%20copy/" rel="alternate" type="text/html"/>
    
    <updated>2019-02-06T21:00:00-00:00</updated>
    <id>https://dor.ky/posts/2019/02/laravel-nova-trim-fields-pattern%20copy/</id>
    <content type="html">&lt;p&gt;In a &lt;a href=&quot;https://dor.ky/tag/nova/&quot;&gt;Laravel Nova&lt;/a&gt; based project I had a list of domains that&lt;br&gt;
sometimes grew to take up most of the row it was in. I discovered the following&lt;br&gt;
pattern to show a limited field on the index view and a full field on the edit&lt;br&gt;
view using a combination of &lt;code&gt;onlyOnIndex()&lt;/code&gt; and &lt;code&gt;hideFromIndex()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;Text&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;Domains&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;additional_domains&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;onlyOnIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;displayUsing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;str_limit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;100&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;...&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;withMeta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;extraAttributes&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;readonly&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token boolean constant&quot;&gt;true&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then a second field that is hidden from the index using &lt;code&gt;hideFromIndex()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;Text&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;SSL Domains&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;ssl_additional_domains&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;   &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hideFromIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;   &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;withMeta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;extraAttributes&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;       &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;readonly&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token boolean constant&quot;&gt;true&lt;/span&gt;&lt;br&gt;   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The fields are automatically populated by the system and are shown read-only to&lt;br&gt;
the user so this really helped to tidy up the UI. Hopefully this helps you out&lt;br&gt;
if you need to limit a field you’re displaying when using &lt;a href=&quot;https://dor.ky/tag/nova/&quot;&gt;Laravel Nova&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Exa - A replacement for &#39;ls&#39;</title>
    
    <link href="https://dor.ky/posts/2019/02/exa-replacement-for-ls/" rel="alternate" type="text/html"/>
    
    <updated>2019-02-06T21:00:00-00:00</updated>
    <id>https://dor.ky/posts/2019/02/exa-replacement-for-ls/</id>
    <content type="html">&lt;p&gt;Exa is a drop in replacement for your Mac’s standard tool ‘ls’. It provides a wider screen listing over ls along with useful extras like Git information. In the screenshot below you can see a &lt;code&gt;N&lt;/code&gt; depicting new file within the posts directory.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://static.dor.ky/old-blog/posts/exa.png&quot; alt=&quot;A screenshot of Exa&quot; title=&quot;Exa&quot;&gt;&lt;/p&gt;
&lt;p&gt;It features really &lt;a href=&quot;https://the.exa.website/features/colours&quot;&gt;useful colour coding&lt;/a&gt; that takes a short while to get used to but after that allow quick identifying of files and runs on a whole host of different operating systems too.&lt;/p&gt;
&lt;p&gt;I’m that much of a fan for exa, I’ve added it to my &lt;a href=&quot;https://dor.ky/recommendations/#homebrew&quot;&gt;recommendations&lt;/a&gt; page with other great software.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel Forge - LetsEncrypt Certificates Failing to Renew</title>
    
    <link href="https://dor.ky/posts/2019/02/laravel-forge-letsencrypt-failing-to-renew/" rel="alternate" type="text/html"/>
    
    <updated>2019-02-06T21:00:00-00:00</updated>
    <id>https://dor.ky/posts/2019/02/laravel-forge-letsencrypt-failing-to-renew/</id>
    <content type="html">&lt;p&gt;When LetsEncrypt arrived a few years ago, it definitely had one of largest&lt;br&gt;
impacts on the web in living memory. Suddenly everyone could have SSL for their&lt;br&gt;
website with minimal effort.&lt;/p&gt;
&lt;p&gt;Over time, the way that systems like LetsEncrypt have to change the way they&lt;br&gt;
work for operational and security reasons. One of these recent changes means&lt;br&gt;
that your existing issued certificates may cease to renew. The reason for this&lt;br&gt;
is because the TLS-SNI-01 challenge has been revoked.&lt;/p&gt;
&lt;p&gt;You can see plenty of posts around the web &lt;a href=&quot;https://community.letsencrypt.org/t/renew-certificate-certbot-issue-how-to-use-http-01-instead-of-tls-sni-01/38112&quot;&gt;discussing the change&lt;/a&gt; and the fix isn’t too painful to implement.&lt;/p&gt;
&lt;p&gt;For Laravel Forge and other Ubuntu 16 compatible systems, you can run the&lt;br&gt;
following commands to upgrade your version of certbot and get back to issuing&lt;br&gt;
your certificates:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; update&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; software-properties-common&lt;br&gt;add-apt-repository universe&lt;br&gt;add-apt-repository ppa:certbot/certbot&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; update&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; certbot python3-certbot-nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run &lt;code&gt;certbot&lt;/code&gt; and it’ll prompt you with a list of your sites to update:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/posts/certbot.png&quot; alt=&quot;A screenshot of Certbot&quot; title=&quot;Certbot&quot;&gt;&lt;/p&gt;
&lt;p&gt;From there you’ll be able to issue certificates as normal and auto-renewals&lt;br&gt;
should succeed.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Thoughts about Domain Registration</title>
    
    <link href="https://dor.ky/posts/2019/01/thoughts-about-domain-registration/" rel="alternate" type="text/html"/>
    
    <updated>2019-01-09T20:00:00-00:00</updated>
    <id>https://dor.ky/posts/2019/01/thoughts-about-domain-registration/</id>
    <content type="html">&lt;p&gt;The following five points are issues that I believe should push people into taking their domain names into their own control.&lt;/p&gt;
&lt;h3 id=&quot;refusal-to-transfer&quot;&gt;Refusal to transfer&lt;/h3&gt;
&lt;p&gt;The first problem that can occur is when you decide to change your developers, if they have your domain names then you will have to negotiate the release of them to you.&lt;/p&gt;
&lt;h3 id=&quot;critical-services-are-out-of-your-control&quot;&gt;Critical services are out of your control&lt;/h3&gt;
&lt;p&gt;Along with your domain name there is likely business critical services like email that are attached to your domain. You should know exactly where these services are being provided from and how to administer/control these. If you have an employee that goes rouge and you need to disable email services in an emergency - you need to be prepared for such an event.&lt;/p&gt;
&lt;h3 id=&quot;developer-could-go-into-administration-or-cease-working&quot;&gt;Developer could go into administration or cease working&lt;/h3&gt;
&lt;p&gt;Along with the previous point there are plenty of reasons why you may suddenly have to access your domain name. If your hosting company goes into administration and you need to transfer your website immediately - without the domain being in your control neither you or a new developer can get your site/application setup without access.&lt;/p&gt;
&lt;h3 id=&quot;you-should-know%2Funderstand-where-your-domain-name(s)-are&quot;&gt;You should know/understand where your domain name(s) are&lt;/h3&gt;
&lt;p&gt;Along with your domain name, there are other important pieces of your digital infrastructure that you should be aware of. Who provides your domain registration, who provides your DNS services? Who provides your organisations email services? These are all important things that you should know but also be aware of where you can administer them.&lt;/p&gt;
&lt;h3 id=&quot;you-could-be-paying-over-the-odds-for-renewals&quot;&gt;You could be paying over the odds for renewals&lt;/h3&gt;
&lt;p&gt;I’ve seen many domain registration companies who over-charge for the domains they register. It’s a good profit earner for smaller companies. Over the long term, this may be costing you a considerable amount of money. You can find the lowest fees by checking either Google domains or Namecheap. Both charge the lowest possible fee.&lt;/p&gt;
&lt;h3 id=&quot;if-it-goes-wrong&quot;&gt;If it goes wrong&lt;/h3&gt;
&lt;p&gt;If you’ve got a &lt;code&gt;.co.uk&lt;/code&gt; domain then you can raise a dispute with &lt;a href=&quot;https://www.nominet.uk/domain-support/uk-domain-disputes/&quot;&gt;Nominet&lt;/a&gt; - for other TLDs then you’re going to have&lt;br&gt;
to attempt to get in contact with the person who registered the domain.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Goals for 2019</title>
    
    <link href="https://dor.ky/posts/2019/01/30-goals-for-2019/" rel="alternate" type="text/html"/>
    
    <updated>2019-01-01T09:00:27-00:00</updated>
    <id>https://dor.ky/posts/2019/01/30-goals-for-2019/</id>
    <content type="html">&lt;p&gt;Each year I usually write myself a set of goals that I’d like to aim for the&lt;br&gt;
next year. I think a lot of people try and set new year resolutions but I never&lt;br&gt;
felt too compelled to do that (or to keep at them).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Finish financial changes&lt;/li&gt;
&lt;li&gt;Lose weight and go back down two waist sizes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dor.ky/2018/12/30/14-books-for-2019.html&quot;&gt;Read at least 14 books over the calendar year&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;See a sunrise/sunset with my partner&lt;/li&gt;
&lt;li&gt;Learn and heavily integrate a new tech, either Vue or React.&lt;/li&gt;
&lt;li&gt;Go to two music concerts (George Ezra booked for March)&lt;/li&gt;
&lt;li&gt;Launch a new SaaS app&lt;/li&gt;
&lt;li&gt;Two full (at least 10 day) vacations&lt;/li&gt;
&lt;li&gt;Hip replacement and recovery&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think these are all hopefully achievable and within my control (apart from&lt;br&gt;
hip replacement but my doctors and surgeon is fairly certain that’ll be very&lt;br&gt;
early 2019).&lt;/p&gt;
&lt;p&gt;I’ll come back through the year and update this list and mark each item&lt;br&gt;
&lt;span class=&quot;completed&quot;&gt;completed&lt;/span&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>14 Books for 2019</title>
    
    <link href="https://dor.ky/posts/2018/12/14-books-for-2019/" rel="alternate" type="text/html"/>
    
    <updated>2018-12-30T21:07:20-00:00</updated>
    <id>https://dor.ky/posts/2018/12/14-books-for-2019/</id>
    <content type="html">&lt;p&gt;One of my &lt;a href=&quot;https://dor.ky/goals-for-2019/&quot;&gt;goals for 2019&lt;/a&gt; is to read at least 14 books. This post tracks the progress of that goal.&lt;/p&gt;
&lt;h4&gt;Current &amp;amp; Completed&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class=&quot;completed&quot;&gt;How to be a Footballer by Peter Crouch&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;completed&quot;&gt;Day the World Came to Town: 9/11 in Gander, Newfoundland by Jim DeFede&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Zucked by Roger McNamee&lt;/li&gt;
&lt;li&gt;The Shortest History of Germany by James Hawes&lt;/li&gt;
&lt;li&gt;Creativity, Inc.: Overcoming the Unseen Forces That Stand in the Way of True Inspiration by Ed Catmull&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Planned&lt;/h4&gt;
&lt;p&gt;The following list of books are ones that I’m planning to read in the future. You&lt;br&gt;
can also check out &lt;a href=&quot;https://www.goodreads.com/user/show/73717117-scott&quot;&gt;my profile on Goodreads&lt;/a&gt; where it’s likely to be a bit more&lt;br&gt;
up to date than this list.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.co.uk/Abundance-Future-Better-Than-Think/dp/1451695764&quot;&gt;Abundance: The Future Is Better Than You Think by Peter H. Diamandis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.co.uk/Hit-Refresh-Memoir-Microsofts-CEO/dp/000824765X&quot;&gt;Hit Refresh by Satya Nadella&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.co.uk/Short-History-Nearly-Everything-Bryson/dp/1784161853&quot;&gt;A Short History of Nearly Everything by Bill Bryson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.co.uk/Introducing-Statistics-Graphic-Guide-ebook/dp/B00KFEK0OC&quot;&gt;Introducing Statistics: A Graphic Guide by Eileen Magnello&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.co.uk/Things-that-Nobody-Knows-Everything-ebook/dp/B008J2G8PM&quot;&gt;The Things that Nobody Knows: 501 Mysteries of Life, the Universe and Everything by William Hartston&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Customising Exports for the &#39;Laravel Nova Excel&#39; Package</title>
    
    <link href="https://dor.ky/posts/2018/12/customising-exports-for-the-laravel-nova-excel-package/" rel="alternate" type="text/html"/>
    
    <updated>2018-12-27T13:42:50-00:00</updated>
    <id>https://dor.ky/posts/2018/12/customising-exports-for-the-laravel-nova-excel-package/</id>
    <content type="html">&lt;p&gt;I recently worked on a project that needed an export for an Orders view within a Laravel Nova panel. If you have simple requirements, for example, exporting all fields with titles – that is relatively simple to produce. However, I needed to update fields and merge others with some other custom changes.&lt;/p&gt;
&lt;p&gt;In short, I moved the export logic into its own &lt;a href=&quot;https://nova.laravel.com/docs/1.0/actions/defining-actions.html&quot;&gt;Laravel Nova action&lt;/a&gt; called &lt;code&gt;ExportOrders&lt;/code&gt;. and added this into the Nova Resource actions like so:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;App&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Nova&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;App&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Nova&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Actions&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;ExportOrders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Order&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Resource&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// snipped..&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/**&lt;br&gt;     * Get the actions available for the resource.&lt;br&gt;     *&lt;br&gt;     * @param  \Illuminate\Http\Request  $request&lt;br&gt;     * @return array&lt;br&gt;     */&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Request &lt;span class=&quot;token variable&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ExportOrders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, I created the above-named file at &lt;code&gt;app/Nova/Actions/ExportOrders.php&lt;/code&gt; to define the headings and map the fields to their corresponding export fields:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;App&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Nova&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Actions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;App&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Models&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;Maatwebsite&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Excel&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Concerns&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;WithHeadings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;Maatwebsite&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Excel&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Concerns&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;WithMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;Maatwebsite&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;LaravelNovaExcel&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;Actions&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;DownloadExcel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ExportOrders&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DownloadExcel&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WithMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WithHeadings&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/**&lt;br&gt;     * @return array&lt;br&gt;     */&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;headings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;internal_order_id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;created_at&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;stripe_transaction_id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;buyer_name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;buyer_email&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;billing_address&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;delivery_name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;delivery_address&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;giftcard_amount&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;total_paid&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;message&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token single-quoted-string string&quot;&gt;&#39;status&#39;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/**&lt;br&gt;     * @param $order&lt;br&gt;     *&lt;br&gt;     * @return array&lt;br&gt;     */&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;transaction_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;buyer_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;buyer_email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;billing_address&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;recipient_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;delivery_address&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token variable&quot;&gt;$order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;status&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Initially I’d added more functionality within this class to merge fields and add custom export but in the end, I decided to move a lot of these field customisations into &lt;a href=&quot;https://laravel.com/docs/5.7/eloquent-mutators#accessors-and-mutators&quot;&gt;Eloquent accessors&lt;/a&gt; instead. This meant that when they were accessed in the Nova panel, exports or anywhere else they became consistent.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Easy Screen Capture on macOS with Giphy Capture</title>
    
    <link href="https://dor.ky/easy-screen-capture-on-macos-with-giphy-capture/" rel="alternate" type="text/html"/>
    
    <updated>2018-09-11T20:16:45-00:00</updated>
    <id>https://dor.ky/easy-screen-capture-on-macos-with-giphy-capture/</id>
    <content type="html">&lt;p&gt;I recently asked on Twitter on what people used for screen capturing. I&lt;br&gt;
actually wanted terminal recording to highlight some commands being ran for a&lt;br&gt;
talk about serverless. I then came across the brilliant&lt;br&gt;
&lt;a href=&quot;https://giphy.com/apps/giphycapture&quot;&gt;Giphy Capture app&lt;/a&gt; and it’s so&lt;br&gt;
simple to use and produces perfect results every time.&lt;/p&gt;
&lt;p&gt;If you need to record your screen for whatever reason on your Mac then I can&lt;br&gt;
highly recommend it.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Thoughts about Mastodon</title>
    
    <link href="https://dor.ky/thoughts-about-mastodon/" rel="alternate" type="text/html"/>
    
    <updated>2018-09-08T11:51:23-00:00</updated>
    <id>https://dor.ky/thoughts-about-mastodon/</id>
    <content type="html">&lt;p&gt;I’ve seen quite a few people posting to Twitter recently that they’ve tried or are actively trying out Mastodon as an alternative to Twitter. This gave me the chance to actually have a few good conversations on the subject and I decided to note down some observations from what I’ve seen. I’m going to preface this and expect that you have an understanding of what Mastodon is – if you don’t then read this &lt;a href=&quot;https://webinista.com/updates/meet-mastodon/&quot;&gt;‘Meet Mastodon’ by Tiffany Brown&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Twitter (along with most social networks) can be a very toxic place. Recently an effort has been made to counteract this but I don’t think that has been anywhere near successful. The toxicity problem isn’t just confined to Twitter though – you can head over to Facebook, Reddit and YouTube among others and see the same on those platforms. I’d even go as far as saying the same toxicity is present in the developer community as well which for a long time felt like it didn’t have that problem. I think as development has become more commonplace it’s inherently gained some of the unpleasant aspects of society and that transcends every method of communication.&lt;/p&gt;
&lt;p&gt;Mastodon prides itself on giving users better control of protecting themselves within the social environment. Users can not only block other users of the same instance – they can block entire instances. There are additional controls built in but like anything it isn’t, can’t and won’t ever be foolproof. I think headlines like Motherboards ‘&lt;a href=&quot;https://motherboard.vice.com/en_us/article/783akg/mastodon-is-like-twitter-without-nazis-so-why-are-we-not-using-it&quot;&gt;Mastodon is like twitter without the nazis&lt;/a&gt;’ don’t help the situation and give a false sense of safety – each and every platform suffers from toxicity. Mastodon is still small enough that it hasn’t attracted the bad crowds yet (I have absolutely no doubts that there are instances already around that are dedicated to horrendous things).&lt;/p&gt;
&lt;p&gt;It’s a little like when folks used to say Mac’s wouldn’t get viruses because they weren’t targeted – the market share was too small for hackers to care. Once the Mac and iOS platforms both got larger they became attack targets fairly quickly. Mastodon will be no different to those.&lt;/p&gt;
&lt;h2 id=&quot;prominent-trying-out&quot;&gt;Prominent Trying Out&lt;/h2&gt;
&lt;p&gt;I’ve seen &lt;a href=&quot;https://finertech.com/&quot;&gt;David Chartier&lt;/a&gt;, &lt;a href=&quot;https://ericlbarnes.com/2018/09/07/mastodon-first-thoughts/&quot;&gt;Eric Barnes&lt;/a&gt;, &lt;a href=&quot;https://ianlandsman.com/&quot;&gt;Ian Landsman&lt;/a&gt; among others testing out Mastodon recently.&lt;/p&gt;
&lt;h2 id=&quot;brand-use&quot;&gt;Brand Use&lt;/h2&gt;
&lt;p&gt;Part of the conversation I had with Eric was that Mastodon just doesn’t suit a brand or personal brand presence anywhere near as well as Twitter. If you instruct someone to follow @ericlbarnes on Twitter then it is fairly easy and failsafe to do so. Mastodon suffers the same problem as ICQ did. In the days of ICQ, you had to remember a long number which was your identifier – mine was 32646413. Not easy to remember, but still slightly easier than Mastodon to find the right person.&lt;/p&gt;
&lt;p&gt;The next issue along is verification and proving that someone who says they are X really is that person. There is no built-in mechanism to verify that a person is exactly who they say they are within Mastodon. Usernames on Mastodon look a lot like a combination or a twitter username and email address. For example, these three could be Elon Musk:&lt;/p&gt;
&lt;p&gt;@elon@elonmusk.com&lt;/p&gt;
&lt;p&gt;@elon@tesla.com&lt;/p&gt;
&lt;p&gt;@elon@spacex.com&lt;/p&gt;
&lt;p&gt;There is zero chance of you verifying which (if any) is the real Elon Musk. Twitter solved this by adding a blue mark next to profiles that they had independently verified but there is no such process with Mastodon.&lt;/p&gt;
&lt;p&gt;So back to Eric, there could be an @ericlbarnes located on the more popular mastodon.social instance, or mastodon.cloud or even &lt;a href=&quot;http://ericlbarnes.com/&quot;&gt;ericlbarnes.com&lt;/a&gt; – there is no method to verify which actually is Eric so there isn’t a canonical place for people to find brand Eric.&lt;/p&gt;
&lt;p&gt;The closest that people have come to be able to do this is writing a page on their website detailing which user and instance they are. Straight away, you’re making people jump through hoops to do something that should be quick and easy. That makes it a much tougher sell to someone to use Mastodon as a brand communication tool.&lt;/p&gt;
&lt;h1&gt;Smaller Communities &amp;amp; Closer Discourse&lt;/h1&gt;
&lt;p&gt;I’ve used Mastodon for quite a while and the thing that still sticks with me to this day is that it really feels like there is a value of conversation. I think part of that comes from it being a smaller environment but the where Twitter seems to have a post-and-forget feel – Mastodon has a conversation feel.&lt;/p&gt;
&lt;p&gt;A lot of people including Eric think that Mastodon will die out soonish with the likes of Myspace, Digg et all but I think that its resonation with getting back to the conversation will make it stick for a lot of people.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Freeze - A Mac Client for Amazon Glacier</title>
    
    <link href="https://dor.ky/freeze-a-mac-client-for-amazon-glacier/" rel="alternate" type="text/html"/>
    
    <updated>2018-08-26T16:23:40-00:00</updated>
    <id>https://dor.ky/freeze-a-mac-client-for-amazon-glacier/</id>
    <content type="html">&lt;p&gt;I tested a couple of recommendations for AWS’s Glacier and settled upon&lt;br&gt;
‘&lt;a href=&quot;https://www.freezeapp.net/&quot;&gt;Freeze&lt;/a&gt;‘. It’s reasonably&lt;br&gt;
priced, great to use and has every feature you’ll need.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Pushing Ottomatik Webhooks to Slack via Apache IBM Cloud Functions OpenWhisk</title>
    
    <link href="https://dor.ky/pushing-ottomatik-webhooks-to-slack-via-apache-ibm-cloud-functions-openwhisk/" rel="alternate" type="text/html"/>
    
    <updated>2018-07-21T15:57:28-00:00</updated>
    <id>https://dor.ky/pushing-ottomatik-webhooks-to-slack-via-apache-ibm-cloud-functions-openwhisk/</id>
    <content type="html">&lt;p&gt;The backup service Ottomatik implemented webhooks last year (at my request, ha!) to send success or failure payloads to a URL of your choice. As Ottomatik doesn’t yet provide a Slack integration. Most teams around the world use Slack to pipe notifications into their channels and it’s a pretty good way of doing things.&lt;/p&gt;
&lt;p&gt;You’re going to need to set up a webhook for Slack &lt;a href=&quot;https://issetio.slack.com/apps/A0F7XDUAZ-incoming-webhooks&quot;&gt;which you can do on their site&lt;/a&gt;. To make things easier, you can use serverless project to make dealing with serverless providers easier. Follow the install steps listed on &lt;a href=&quot;https://serverless.com/framework/docs/providers/openwhisk/guide/quick-start/&quot;&gt;serverless website&lt;/a&gt; to get started.&lt;/p&gt;
&lt;p&gt;We’ll use Guzzle to send our API call to Slack. We’ll put all of the code that executes our function in a file named &lt;code&gt;handler.php&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can clone this repository &lt;a href=&quot;https://github.com/ssx/openwhisk-ottomatik-to-slack&quot;&gt;ssx/openwhisk-ottomatik-to-slack&lt;/a&gt; as a quick start.&lt;/p&gt;
&lt;p&gt;Update the URL for the Slack webhook and we’ll then push our function up.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sls deploy&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Here’s everything in one go:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/ssx/openwhisk-ottomatik-to-slack/raw/master/tldr.gif?raw=true&quot; alt=&quot;tl;dr&quot;&gt;&lt;/p&gt;
&lt;p&gt;which will return a webhook for you to use in Ottomatik:&lt;/p&gt;
&lt;img class=&quot;alignnone wp-image-1832 size-large&quot; src=&quot;https://dor.ky/app/uploads/2018/07/ottomatik-webhook-1024x427.png&quot; alt=&quot;&quot; width=&quot;1024&quot; height=&quot;427&quot; srcset=&quot;https://dor.ky/app/uploads/2018/07/ottomatik-webhook-1024x427.png 1024w, https://dor.ky/app/uploads/2018/07/ottomatik-webhook-300x125.png 300w, https://dor.ky/app/uploads/2018/07/ottomatik-webhook-768x320.png 768w&quot; sizes=&quot;(max-width: 1024px) 100vw, 1024px&quot;&gt;
&lt;p&gt;If everything went to plan, you’ll now get near real time updates on how your backups are performing.&lt;/p&gt;
&lt;p&gt;Comments, idea and thoughts welcome over on Github.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Ubuntu Zesty Fails to &#39;apt-get update&#39;</title>
    
    <link href="https://dor.ky/ubuntu-zesty-fails-to-apt-get-update/" rel="alternate" type="text/html"/>
    
    <updated>2018-05-14T17:23:33-00:00</updated>
    <id>https://dor.ky/ubuntu-zesty-fails-to-apt-get-update/</id>
    <content type="html">&lt;p&gt;Ubuntu Zesty no longer is a supported version of Ubuntu, you’ll need to&lt;br&gt;
update &lt;code&gt;apt/sources.list&lt;/code&gt; to this:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;deb http://old-releases.ubuntu.com/ubuntu/ zesty main restricted universe multiverse&lt;br&gt;deb http://old-releases.ubuntu.com/ubuntu/ zesty-updates main restricted universe multiverse&lt;br&gt;deb http://old-releases.ubuntu.com/ubuntu/ zesty-security main restricted universe multiverse&lt;br&gt;&lt;br&gt;deb http://old-releases.ubuntu.com/ubuntu/ zesty-proposed main restricted universe multiverse&lt;br&gt;deb http://old-releases.ubuntu.com/ubuntu/ zesty-backports main restricted universe multiverse&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;apt-get clean all&lt;/code&gt; after updating that file and you’ll be able to&lt;br&gt;
upgrade as normal.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Clear Bash History</title>
    
    <link href="https://dor.ky/clear-bash-history/" rel="alternate" type="text/html"/>
    
    <updated>2018-04-19T14:51:45-00:00</updated>
    <id>https://dor.ky/clear-bash-history/</id>
    <content type="html">&lt;p&gt;Quick way to clear bash/shell history:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; /dev/null &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; ~/.bash_history &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;history&lt;/span&gt; -c &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;exit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Deleting Immutable Files on Linux</title>
    
    <link href="https://dor.ky/deleting-immutable-files-on-linux/" rel="alternate" type="text/html"/>
    
    <updated>2018-04-15T13:08:15-00:00</updated>
    <id>https://dor.ky/deleting-immutable-files-on-linux/</id>
    <content type="html">&lt;p&gt;If you have a file such as &lt;code&gt;php-fpm.cgi&lt;/code&gt; that won’t delete no matter what&lt;br&gt;
you try, it’s likely immutable. You can remove the immutable flag using:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;chattr -i file.name&lt;/code&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Easier Git Aliases</title>
    
    <link href="https://dor.ky/easier-git-aliases/" rel="alternate" type="text/html"/>
    
    <updated>2018-04-14T13:01:28-00:00</updated>
    <id>https://dor.ky/easier-git-aliases/</id>
    <content type="html">&lt;p&gt;I recently came across the git-legit project which creates a few easier to&lt;br&gt;
understand aliases for newcomers to Git. Head over to &lt;a href=&quot;http://www.git-legit.org/&quot;&gt;http://www.git-legit.org&lt;/a&gt;&lt;br&gt;
to read and install.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Install older Android SDK Version</title>
    
    <link href="https://dor.ky/install-older-android-sdk-version/" rel="alternate" type="text/html"/>
    
    <updated>2018-04-01T20:49:58-00:00</updated>
    <id>https://dor.ky/install-older-android-sdk-version/</id>
    <content type="html">&lt;p&gt;For a Titanium project I recently needed to install an older version of the Android SDK tools (build tools API 24) to build an old project.&lt;/p&gt;
&lt;p&gt;Find the path to &lt;code&gt;sdkmanager&lt;/code&gt; and then run this command:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;sdkmanager --install &quot;platforms;android-24&quot;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to De-Register iMessage</title>
    
    <link href="https://dor.ky/how-to-de-register-imessage/" rel="alternate" type="text/html"/>
    
    <updated>2018-03-25T22:15:15-00:00</updated>
    <id>https://dor.ky/how-to-de-register-imessage/</id>
    <content type="html">&lt;p&gt;This is quick and easy, head over to &lt;a href=&quot;https://selfsolve.apple.com/deregister-imessage/&quot;&gt;https://selfsolve.apple.com/deregister-imessage/&lt;/a&gt;&lt;br&gt;
and fill in your mobile number. It will then SMS a code which you need to&lt;br&gt;
input into the site and then deactivate iMessage for that number.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>List All Your Digital Ocean Servers IPv4 addresses</title>
    
    <link href="https://dor.ky/list-all-your-digital-ocean-servers-ipv4-addresses/" rel="alternate" type="text/html"/>
    
    <updated>2018-03-07T16:27:15-00:00</updated>
    <id>https://dor.ky/list-all-your-digital-ocean-servers-ipv4-addresses/</id>
    <content type="html">&lt;p&gt;List all Digital Ocean servers IPv4 addresses using &lt;a href=&quot;https://github.com/digitalocean/doctl&quot;&gt;doctl homebrew package&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;doctl compute droplet list --format PublicIPv4 &gt; ips.txt&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>AWS S3 Recursively List Bucket Sizes</title>
    
    <link href="https://dor.ky/aws-s3-recursively-list-bucket-sizes/" rel="alternate" type="text/html"/>
    
    <updated>2018-03-07T16:23:36-00:00</updated>
    <id>https://dor.ky/aws-s3-recursively-list-bucket-sizes/</id>
    <content type="html">&lt;p&gt;Recursively list sizes of your AWS buckets using &lt;a href=&quot;http://brewformulas.org/S3cmd&quot;&gt;s3cmd&lt;/a&gt;:&lt;/p&gt;
&lt;h2 id=&quot;scott%40atlas.local-~-s3cmd-du--h--r-s3%3A%2F%2F-%EE%82%B2-16%3A19%3A223.81335246842g-51-objects-s3%3A%2F%2Fssx-general-backups%2F52.0762854349g-52-objects-s3%3A%2F%2Fssx-archived-client-websites%2F189.562103216g-565-objects-s3%3A%2F%2Fssx-backups-production%2F664.248046875m-1-objects-s3%3A%2F%2Fssx-backups-git%2F7.44284629263g-74-objects-s3%3A%2F%2Fssx-backups-servers-shared%2F238.997132301m-3579-objects-s3%3A%2F%2Fssx-images%2F&quot;&gt;&lt;pre&gt;scott@atlas.local  ~ s3cmd du -H -r s3://                                                                                                                                                                        16:19:22&lt;br&gt;
3.81335246842G 51 objects s3://ssx-general-backups/&lt;br&gt;
52.0762854349G 52 objects s3://ssx-archived-client-websites/&lt;br&gt;
189.562103216G 565 objects s3://ssx-backups-production/&lt;br&gt;
664.248046875M 1 objects s3://ssx-backups-git/&lt;br&gt;
7.44284629263G 74 objects s3://ssx-backups-servers-shared/&lt;br&gt;
238.997132301M 3579 objects s3://ssx-images/&lt;/pre&gt;&lt;/h2&gt;
&lt;p&gt;253.776662782G Total&lt;br&gt;
&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Simple IP Reverse &amp; Info</title>
    
    <link href="https://dor.ky/simple-ip-reverse-info/" rel="alternate" type="text/html"/>
    
    <updated>2018-02-13T10:38:11-00:00</updated>
    <id>https://dor.ky/simple-ip-reverse-info/</id>
    <content type="html">&lt;p&gt;Using &lt;a href=&quot;http://ipinfo.io/&quot;&gt;ipinfo.io&lt;/a&gt;, you can quickly grab some IP data for the current machine:&lt;/p&gt;
&lt;pre&gt;curl ipinfo.io&lt;/pre&gt;
&lt;p&gt;This will return you something like:&lt;/p&gt;
&lt;pre&gt;scott@atlas.local ~ curl ipinfo.io                                   
 {
   &quot;ip&quot;: &quot;195.62.123.123&quot;,
   &quot;city&quot;: &quot;Stafford&quot;,
   &quot;region&quot;: &quot;England&quot;,
   &quot;country&quot;: &quot;GB&quot;,
   &quot;loc&quot;: &quot;52.8052,-2.1164&quot;,
   &quot;org&quot;: &quot;AS6717 Internet Central Limited&quot;,
   &quot;postal&quot;: &quot;ST16&quot;
 }&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Apache Set Server Tokens Off</title>
    
    <link href="https://dor.ky/apache-set-server-tokens-off/" rel="alternate" type="text/html"/>
    
    <updated>2018-02-11T13:50:11-00:00</updated>
    <id>https://dor.ky/apache-set-server-tokens-off/</id>
    <content type="html">&lt;pre&gt;ServerSignature Off
ServerTokens Prod&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Apache Set Expires Header for Images/CSS</title>
    
    <link href="https://dor.ky/apache-set-expires-header-for-images-css/" rel="alternate" type="text/html"/>
    
    <updated>2018-02-10T10:49:14-00:00</updated>
    <id>https://dor.ky/apache-set-expires-header-for-images-css/</id>
    <content type="html">&lt;pre&gt;&amp;lt;IfModule mod_expires.c&amp;gt;
ExpiresActive on
ExpiresDefault &quot;access plus 30 seconds&quot;
ExpiresByType text/html &quot;access plus 15 days&quot;
ExpiresByType image/gif &quot;access plus 1 months&quot;
ExpiresByType image/jpg &quot;access plus 1 months&quot;
ExpiresByType image/jpeg &quot;access plus 1 months&quot;
ExpiresByType image/png &quot;access plus 1 months&quot;
ExpiresByType text/js &quot;access plus 1 months&quot;
ExpiresByType text/javascript &quot;access plus 1 months&quot;
&amp;lt;/IfModule&amp;gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Apache Redirect for Canonical Domain</title>
    
    <link href="https://dor.ky/apache-redirect-for-canonical-domain/" rel="alternate" type="text/html"/>
    
    <updated>2018-02-09T18:00:25-00:00</updated>
    <id>https://dor.ky/apache-redirect-for-canonical-domain/</id>
    <content type="html">&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;RewriteEngine on&lt;br&gt;RewriteCond %&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;HTTP_HOST&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;^www.example.com$&lt;br&gt;RewriteRule &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.*&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; https://www.example.com&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;R&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;301&lt;/span&gt;,L&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;RewriteCond %&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;HTTPS&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt;on&lt;br&gt;RewriteRule ^/?&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.*&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; https://%&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;SERVER_NAME&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;R,L&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>SPF Record for No Mail Sending Domain</title>
    
    <link href="https://dor.ky/spf-record-for-no-mail-sending-domain/" rel="alternate" type="text/html"/>
    
    <updated>2018-02-07T21:46:27-00:00</updated>
    <id>https://dor.ky/spf-record-for-no-mail-sending-domain/</id>
    <content type="html">&lt;pre&gt;&quot;v=spf1 -all&quot;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Namecheap SSL Certificate Combining</title>
    
    <link href="https://dor.ky/namecheap-ssl-certificate/" rel="alternate" type="text/html"/>
    
    <updated>2018-02-05T14:28:42-00:00</updated>
    <id>https://dor.ky/namecheap-ssl-certificate/</id>
    <content type="html">&lt;pre&gt;cat example_com.crt COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt &amp;gt;&amp;gt; ssl-bundle.crt&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel Validation Rules</title>
    
    <link href="https://dor.ky/laravel-validation-rules/" rel="alternate" type="text/html"/>
    
    <updated>2017-09-10T14:47:59-00:00</updated>
    <id>https://dor.ky/laravel-validation-rules/</id>
    <content type="html">&lt;p&gt;I’ve noticed over the past few months my usage of the Laravel validation&lt;br&gt;
engine has increased a lot. I’ve even used it in some non-Laravel&lt;br&gt;
applications just because I’m a fan of the interface. I had the idea of&lt;br&gt;
sharing some of the validation rules with the community but there wasn’t&lt;br&gt;
too many people doing the same.&lt;/p&gt;
&lt;p&gt;I created a new project to address this, called&lt;br&gt;
&lt;a href=&quot;https://github.com/laravel-validation-rules/&quot;&gt;Laravel Validation Rules&lt;/a&gt;. You&lt;br&gt;
can follow &lt;a href=&quot;https://twitter.com/laravelvr&quot;&gt;@laravelvr&lt;/a&gt; on Twitter for project&lt;br&gt;
updates, check out the current rules at &lt;a href=&quot;http://laravel-validation-rules.github.io/&quot;&gt;laravel-validation-rules.github.io&lt;/a&gt; to&lt;br&gt;
see if any of the rules can help you in your project.&lt;/p&gt;
&lt;p&gt;If you have your own rule that you think the community would benefit from&lt;br&gt;
having, &lt;a href=&quot;https://laravel-validation-rules.github.io/contributing.html&quot;&gt;please submit it&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Quick Way to Set Telegram Webhook</title>
    
    <link href="https://dor.ky/quick-way-to-set-telegram-webhook/" rel="alternate" type="text/html"/>
    
    <updated>2017-09-09T14:57:08-00:00</updated>
    <id>https://dor.ky/quick-way-to-set-telegram-webhook/</id>
    <content type="html">&lt;p&gt;I needed a small tool recently to set Telegram webhooks quickly over a few projects. You usually just run a curl command to do this but the format is something you have to remember – this is a lot simpler. Just head over to &lt;a href=&quot;https://telegram-set-webhook.tools.dor.ky/&quot;&gt;https://telegram-set-webhook.tools.dor.ky/&lt;/a&gt; to use it.&lt;/p&gt;
&lt;p&gt;If you’d like to verify the source or contribute then you can find the project on Github at &lt;a href=&quot;https://github.com/ssx/telegram-set-webhook&quot;&gt;https://github.com/ssx/telegram-set-webhook&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Docker Based Torrent Client</title>
    
    <link href="https://dor.ky/docker-based-torrent-client/" rel="alternate" type="text/html"/>
    
    <updated>2017-09-04T19:44:23-00:00</updated>
    <id>https://dor.ky/docker-based-torrent-client/</id>
    <content type="html">&lt;p&gt;Easy way to run &lt;a href=&quot;http://rakshasa.github.io/rtorrent/&quot;&gt;rtorrent&lt;/a&gt; in Docker is using &lt;a href=&quot;https://github.com/kfei/docktorrent&quot;&gt;Docktorrent&lt;/a&gt; like this:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;docker run -it \
    -p 81:80 -p 45566:45566 -p 9527:9527/udp \
    --dns 8.8.8.8 \
    -v /rtorrent:/rtorrent \
    -e UPLOAD_RATE=1024 \
    kfei/docktorrent&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Writing a Better README.md</title>
    
    <link href="https://dor.ky/writing-a-better-readme-md/" rel="alternate" type="text/html"/>
    
    <updated>2017-08-26T13:23:16-00:00</updated>
    <id>https://dor.ky/writing-a-better-readme-md/</id>
    <content type="html">&lt;p&gt;A while ago I remember seeing a tweet from Ryan Florence about docuemntation:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
  &lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;
    I think the biggest mistake we all make in docs and tutorials:&lt;br&gt; Not explaining *first* what the goal, or use-case, or desired result is.
  &lt;/p&gt;
  &lt;p&gt;
    — Ryan Florence @ 🐙🤖 (@ryanflorence) &lt;a href=&quot;https://twitter.com/ryanflorence/status/876925128528900097&quot;&gt;June 19, 2017&lt;/a&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Last week I’d seen that Kent C Dodds had a further point on it, which I liked:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
  &lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;
    Here&#39;s the order I use in my projects:
  &lt;/p&gt;
  &lt;p&gt;
    Problem&lt;br&gt; Solution&lt;br&gt; Installation&lt;br&gt; Usage&lt;br&gt; Inspiration&lt;br&gt; Related&lt;br&gt; Thanks&lt;br&gt; License&lt;a href=&quot;https://t.co/nCBk52VOiu&quot;&gt;https://t.co/nCBk52VOiu&lt;/a&gt;
  &lt;/p&gt;
  &lt;p&gt;
    — Kent C. Dodds (@kentcdodds) &lt;a href=&quot;https://twitter.com/kentcdodds/status/877189118572191744&quot;&gt;June 20, 2017&lt;/a&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So going forward I’m planning to use that as a template along with going over some existing projects and modifying those. I think the extra information contained within the problem and solution areas could really help others who are trying to solve their own problem.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Magento Redirection after Store URL Changed</title>
    
    <link href="https://dor.ky/magento-redirection-after-store-url-changed/" rel="alternate" type="text/html"/>
    
    <updated>2017-08-24T12:55:49-00:00</updated>
    <id>https://dor.ky/magento-redirection-after-store-url-changed/</id>
    <content type="html">&lt;p&gt;I recently ran into an issue where a Magento site that had been duplicated for development kept redirecting to the original site URL. Turned out that the culprit was a setting called SSL_OFFLOADED which needed to be turned off.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Tip: Telephone Preference Service</title>
    
    <link href="https://dor.ky/tip-telephone-preference-service/" rel="alternate" type="text/html"/>
    
    <updated>2017-08-22T19:13:32-00:00</updated>
    <id>https://dor.ky/tip-telephone-preference-service/</id>
    <content type="html">&lt;p&gt;If you’re in the UK, you can easily stop a lot of marketing calls by signing up for the Telephone Preference Service. It’s extremely simple to do, send a text message to 85095 with ‘TPS &lt;a href=&quot;mailto:email@address.com&quot;&gt;email@address.com&lt;/a&gt;” – don’t forget to remove the quotes and add your email address in.&lt;/p&gt;
&lt;p&gt;You can find full instructions over on the &lt;a href=&quot;http://www.tpsonline.org.uk/tps/tps_text.html&quot;&gt;TPS website&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Restore Telnet in Mac OS High Sierra 10.13</title>
    
    <link href="https://dor.ky/restore-telnet-in-mac-os-high-sierra-10-13/" rel="alternate" type="text/html"/>
    
    <updated>2017-08-17T15:40:19-00:00</updated>
    <id>https://dor.ky/restore-telnet-in-mac-os-high-sierra-10-13/</id>
    <content type="html">&lt;p&gt;Telnet has been removed from Mac OS High Sierra, but can still be useful for developers to check ports are open etc.&lt;/p&gt;
&lt;p&gt;If you need to enable it, you can do so with Homebrew:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;brew tap theeternalsw0rd/telnet                                                                                                                                                                                                                   
brew install telnet&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Update (10/10/17)&lt;/strong&gt;: I received an email from &lt;a href=&quot;https://www.linkedin.com/in/davidwaitzman&quot;&gt;David Waitzman&lt;/a&gt; in which he notes you can get telnet from an old Time Machine backup and then copy it into /usr/local/bin – I’d recommend that options too if you have a backup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update (25/11/17)&lt;/strong&gt;: I received a second email from Michael Bazik which details how you can install the telnet client directly from GNU provided tarballs:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;curl http://ftp.gnu.org/gnu/inetutils/inetutils-1.9.4.tar.gz -o inetutils-1.9.4.tar.gz
tar xvzf inetutils-1.9.4.tar.gz
cd inetutils-1.9.4
./configure
make
sudo make install

&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Update (05/01/18)&lt;/strong&gt;: Jonny Bradley emailed in to address an issue with installing non homebrew telnet. If you encounter the error:&lt;/p&gt;
&lt;pre&gt;ping: Lacking privilege for raw socket.&lt;/pre&gt;
&lt;p&gt;then you’ll need to chmod ping to allow it permission to run with:&lt;/p&gt;
&lt;pre&gt;sudo chmod a+s /usr/local/bin/ping&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Update (08/02/18)&lt;/strong&gt;: Matthew Ward got in touch to say that you can compile telnet without all of the other gunk that still comes with Mac OS, using the following:&lt;/p&gt;
&lt;pre&gt;# out of the &quot;inet-utils&quot; bundle from GNU, the only utilities it provides
# that Mac doesn&#39;t &quot;natively&quot; are:
#
#   ftp     the ftp client
#   telnet  the telnet client
#
# you don&#39;t need to build the whole set. use the following &quot;configure&quot;
# command line:

./configure --disable-servers --disable-dnsdomainname \
--disable-hostname --disable-ping --disable-ping6 --disable-rcp \
--disable-rexec --disable-rlogin --disable-rsh --disable-logger \
--disable-talk --disable-tftp --disable-whois --disable-ifconfig \
--disable-traceroute
&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>MacOS: Add Message to Lock Screen</title>
    
    <link href="https://dor.ky/macos-add-message-to-lock-screen/" rel="alternate" type="text/html"/>
    
    <updated>2017-06-22T19:38:14-00:00</updated>
    <id>https://dor.ky/macos-add-message-to-lock-screen/</id>
    <content type="html">&lt;p&gt;This is a really good idea about &lt;a href=&quot;http://www.productivityorchard.com/add-lost-and-found-message-to-login-lock-screen&quot;&gt;adding a message to your lock screen&lt;/a&gt; on MacOS with a note on how to contact you in the event your Mac is lost.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Testing Laravel Applications with CircleCI &amp; Dusk</title>
    
    <link href="https://dor.ky/testing-laravel-applications-with-circleci-dusk/" rel="alternate" type="text/html"/>
    
    <updated>2017-05-17T21:01:21-00:00</updated>
    <id>https://dor.ky/testing-laravel-applications-with-circleci-dusk/</id>
    <content type="html">&lt;p&gt;I recently started a new project and wanted to give Laravel’s new test framework Dusk a try. Locally, this was quick to do and it worked first time – however when I then connected up CircleCI I needed to do a little extra work to get up and running. In short, the version of Google Chrome needs updating to a newer version and then things should be running well.&lt;/p&gt;
&lt;p&gt;Firstly, make sure you’re up and running locally and your tests are passing (that’s half the work done, right?). You should have output similar to:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;scott@inex.local / sample-app / master ✔ : php artisan dusk
PHPUnit 5.7.19 by Sebastian Bergmann and contributors.

...                                                               3 / 3 (100%)

Time: 15.18 seconds, Memory: 16.00MB

OK (3 tests, 3 assertions)
&lt;/pre&gt;
&lt;p&gt;So, we’re all good at this point. Next, get your circle.yml file looking something like the following:&lt;/p&gt;
&lt;pre class=&quot;lang:yaml decode:true&quot;&gt;machine:
  pre:
    - sudo apt-get update; USE_PRECOMPILE=true sudo -E circleci-install php 7.1.0
  timezone:
    Europe/London
  php:
    version: 7.1.0
  environment:
    APP_ENV: &quot;testing&quot;
  hosts:
      testing: 127.0.0.1

general:
  artifacts:
    - &quot;tests/Browser/screenshots&quot;
    - &quot;tests/Browser/console&quot;

dependencies:
  pre:
    - rm /opt/circleci/php/$(phpenv global)/etc/conf.d/xdebug.ini

  override:
    - composer install
    - wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
    - sudo sh -c &#39;echo &quot;deb http://dl.google.com/linux/chrome/deb/ stable main&quot; &amp;gt;&amp;gt; /etc/apt/sources.list.d/google-chrome.list&#39;
    - sudo apt-get update
    - sudo apt-get install google-chrome-stable

test:
  pre:
    - &quot;./vendor/laravel/dusk/bin/chromedriver-linux&quot;:
        background: true
    - cp .env.testing .env
    - cp .env.testing .env.dusk
    - &quot;php artisan serve&quot;:
        background: true

  override:
    - mkdir -p $CIRCLE_TEST_REPORTS/phpunit
    - php artisan dusk --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit.xml tests&lt;/pre&gt;
&lt;p&gt;This will make sure you’re using PHP 7.1, start the site running in the background and allow dusk to run. You’ll need to make sure that the APP_URL value in your .env.testing file is pointing to 127.0.0.1. In the example above, we’re making sure that CircleCI adds an entry to /etc/hosts for ‘testing’.&lt;/p&gt;
&lt;p&gt;Providing your tests now work, you’ll have a big green bar in CircleCI.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Use &#39;net-alias&#39; in Docker for Easy Round Robin Load Balancing</title>
    
    <link href="https://dor.ky/use-net-alias-in-docker-for-easy-round-robin-load-balancing/" rel="alternate" type="text/html"/>
    
    <updated>2017-05-17T20:36:05-00:00</updated>
    <id>https://dor.ky/use-net-alias-in-docker-for-easy-round-robin-load-balancing/</id>
    <content type="html">&lt;p&gt;Something I picked up on a few days ago was using Docker’s –net-alias command (or docker-compose equivalent) for cheap and easy round robin load balancing.&lt;/p&gt;
&lt;p&gt;For example, start two elasticsearch containers with –net-alias search and from within the network, using the ‘search’ as the DNS name for connecting, you’d get 1 of the 2 servers at random.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Tool to Create Mastodon OAuth2 Applications in Your Browser</title>
    
    <link href="https://dor.ky/tool-to-create-mastodon-oauth2-applications-in-your-browser/" rel="alternate" type="text/html"/>
    
    <updated>2017-04-19T20:35:17-00:00</updated>
    <id>https://dor.ky/tool-to-create-mastodon-oauth2-applications-in-your-browser/</id>
    <content type="html">&lt;p&gt;At the moment, there isn’t a user friendly way of setting up new OAuth2 applications for use with Mastodon. You need to make an API request to do so. To help, I’ve written a small tool which allows you to do this securely in your browser.&lt;/p&gt;
&lt;p&gt;You can use the tool at &lt;a href=&quot;https://mastodon-create-app.ssx.tools/&quot;&gt;mastodon-create-app.ssx.tools&lt;/a&gt; or you can grab the source yourself from Github at &lt;a href=&quot;https://github.com/ssx/mastodon-create-app&quot;&gt;ssx/mastodon-create-app&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have any ideas or feedback, please open an issue on the repo.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Github &amp; Hide Files from Commit Diffs</title>
    
    <link href="https://dor.ky/github-hide-files-from-commit-diffs/" rel="alternate" type="text/html"/>
    
    <updated>2017-04-16T11:26:53-00:00</updated>
    <id>https://dor.ky/github-hide-files-from-commit-diffs/</id>
    <content type="html">&lt;p&gt;This is a &lt;a href=&quot;https://wynnnetherland.com/journal/suppress-generated-javascript-on-github-diffs/&quot;&gt;really nice tip for tidying up git diff&lt;/a&gt;‘s on Github (I think it’ll work for Gitlab etc too), you can add the following line to .gitattributes file:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;dist/* linguist-generated&lt;/pre&gt;
&lt;p&gt;and this will hide all files in the dist/ directory from the commit diff.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Appcelerator Titanium Starting an Intent/Activity Not Firing</title>
    
    <link href="https://dor.ky/appcelerator-titanium-starting-an-intentactivity-not-firing/" rel="alternate" type="text/html"/>
    
    <updated>2017-04-15T20:02:54-00:00</updated>
    <id>https://dor.ky/appcelerator-titanium-starting-an-intentactivity-not-firing/</id>
    <content type="html">&lt;p&gt;If you’re a user of intents with Android and Appcelerator’s Titanium product, you may have instances where your intents don’t fire as you expect. A lot of sample code around the web for starting intents looks something like this:&lt;/p&gt;
&lt;pre class=&quot;lang:js decode:true &quot;&gt;var intent = Ti.Android.createIntent({
    action: Ti.Android.ACTION_MAIN
});
intent.addCategory(Ti.Android.CATEGORY_LAUNCHER);
Ti.Android.currentActivity.startActivity(intent);&lt;/pre&gt;
&lt;p&gt;The problem with arises when sometimes Ti.Android.currentActivity doesn’t correctly hold the current activity. When you then attempt to start an intent from the current activity, it does nothing. The way around this is to call startActivity from the current view, like this:&lt;/p&gt;
&lt;pre class=&quot;lang:js decode:true &quot;&gt;$.nameOfCurrentView.startActivity(intent);&lt;/pre&gt;
&lt;p&gt;Which will fire the new intent every time.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Continuous Integration Testing an Appcelerator Titanium Mobile Application</title>
    
    <link href="https://dor.ky/continuous-integration-testing-an-appcelerator-titanium-mobile-application/" rel="alternate" type="text/html"/>
    
    <updated>2017-04-15T09:10:27-00:00</updated>
    <id>https://dor.ky/continuous-integration-testing-an-appcelerator-titanium-mobile-application/</id>
    <content type="html">&lt;p&gt;I’ve recently been looking at unit testing some isolated components for a mobile application I’m working on. Part of the application is a calculations engine which I wanted to test against a known set of sample data and results.&lt;/p&gt;
&lt;p&gt;There have been many attempts through the community at putting widely &lt;a href=&quot;https://www.quora.com/What-are-best-titanium-appcelerator-unit-testing-frameworks&quot;&gt;accepted testing frameworks&lt;/a&gt; throughout the last few years, but none felt too akin to what I wanted or how I wanted it to work. Most of the testing frameworks out there such as &lt;code&gt;timocha&lt;/code&gt; run within the application via a simulator and this was something I wanted to avoid.&lt;/p&gt;
&lt;p&gt;For version control I use both &lt;a href=&quot;https://github.com/&quot;&gt;Github&lt;/a&gt; for personal projects and then &lt;a href=&quot;https://gitlab.com/&quot;&gt;Gitlab&lt;/a&gt; at work and for my larger personal projects. I wanted a solution that could run within Gitlab’s CI runner – which I use Docker.&lt;/p&gt;
&lt;p&gt;I began by creating a &lt;code&gt;Dockerfile&lt;/code&gt; which included the things needed to build an application. There were a few road blocks in the way. The image needed to have node, npm, Oracle Java 8, android-idk-linux and a few npm packages such as &lt;code&gt;appcelerator&lt;/code&gt;, &lt;code&gt;titanium&lt;/code&gt;, &lt;code&gt;jasmine&lt;/code&gt;, &lt;code&gt;tisdk&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Firstly, the &lt;code&gt;appc&lt;/code&gt; command will require a username and password to login to to Appcelerator’s platform to fetch an SDK and produce a build – this wasn’t ideal. The &lt;code&gt;appc&lt;/code&gt; tool won’t run under the &lt;code&gt;root&lt;/code&gt; user (for good reason) which also meant employing &lt;code&gt;runuser&lt;/code&gt; a few times to get commands to run.&lt;/p&gt;
&lt;p&gt;A few very helpful conversations with &lt;a href=&quot;https://twitter.com/adampax&quot; title=&quot;Adam Paxton&quot;&gt;Adam Paxton&lt;/a&gt; highlighted the useful &lt;code&gt;tisdk&lt;/code&gt; npm package which will fetch and install SDKs and the open source &lt;code&gt;ti&lt;/code&gt; NPM package can perform the open source version of &lt;code&gt;appc&lt;/code&gt; which includes producing a build. You’ll also need to install some gcc libraries as well (they’re in the Dockerfile).&lt;/p&gt;
&lt;p&gt;The producing a build part is needed with &lt;code&gt;tiunit&lt;/code&gt; so that you can correctly include any alloy resources that you need (in my case, I had used &lt;code&gt;alloy/moment&lt;/code&gt; in a few places which I ended up mocking instead. For reference, you can build your application using (adjust for platform you’re using):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;appc run -p android -b&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In the end, I managed to get my &lt;code&gt;tiunit&lt;/code&gt; tests running, I’ll follow up with a sample application and test case for you to follow along with.&lt;/p&gt;
&lt;p&gt;You can use the image from Dockerhub at &lt;a href=&quot;https://hub.docker.com/r/hellossx/appcelerator-ci/&quot;&gt;hellossx/appcelerator-ci&lt;/a&gt; which is built automatically from the Github repo &lt;a href=&quot;https://github.com/ssx/docker-appcelerator-ci&quot;&gt;ssx/docker-appcelerator-ci&lt;/a&gt;. I used the following &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; configuration to have it run my tests:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;image: hellossx/appcelerator-ci

variables:
  JAVA_HOME: &amp;quot;/usr/lib/jvm/java-8-oracle/&amp;quot;
  ANDROID_HOME: &amp;quot;/usr/local/android/android-sdk-linux&amp;quot;

cache:
  key: &amp;quot;costings_app&amp;quot;
  untracked: true

stages:
  - test

npm_tasks:
  stage: test
  script:
    - npm install

run_jasmine_tests:
  stage: test
  script:
    - tisdk install 6.0.3.GA
    - ti build -p android -b
    - npm test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you prefer that as a gist, you &lt;a href=&quot;https://gist.github.com/ssx/8aa5675dea2793f8533c57b4728929eb&quot;&gt;can view it here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;notes%3A&quot;&gt;Notes:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.appcelerator.com/mobile-app-development-products/hyperloop/&quot;&gt;Hyperloop&lt;/a&gt; is a no-no using this method, without introducing your Appcelerator username/password into the scripts.&lt;/li&gt;
&lt;li&gt;Introducing Appcelerator username/passwords would be trivial using Gitlab’s secret variables within their CI.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Magento 2 Interceptors</title>
    
    <link href="https://dor.ky/magento-2-interceptors/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-28T17:04:40-00:00</updated>
    <id>https://dor.ky/magento-2-interceptors/</id>
    <content type="html">&lt;p&gt;A colleague at work told me about the way you can use interceptors in Magento 2 to wrap up before/after functionality of existing classes. This is a pretty good overview of &lt;a href=&quot;https://www.yireo.com/blog/1845-magento-2-interceptors-under-php-7&quot;&gt;how that works written by Jisse Reitsma&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Zapier&#39;s CLI Tool for Creating Zaps</title>
    
    <link href="https://dor.ky/zapiers-cli-tool-for-creating-zaps/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-27T18:20:04-00:00</updated>
    <id>https://dor.ky/zapiers-cli-tool-for-creating-zaps/</id>
    <content type="html">&lt;p&gt;This is a pretty neat new feature from Zapier to allow developers to build the little modules that connect apps together. They’ve released a CLI tool which will scaffold an app. You can take a look over on their developer blog &lt;a href=&quot;https://zapier.com/engineering/zapier-command-line-interface/&quot;&gt;in this post&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Removing Vue From Default Laravel Installations</title>
    
    <link href="https://dor.ky/removing-vue-from-default-laravel-installations/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-26T17:56:28-00:00</updated>
    <id>https://dor.ky/removing-vue-from-default-laravel-installations/</id>
    <content type="html">&lt;p&gt;Matt Stauffer has a great post on &lt;a href=&quot;https://mattstauffer.co/blog/removing-all-vue-dependencies-from-laravel&quot;&gt;how to remove Vue from default Laravel&lt;/a&gt; installations.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>App Performance Low Hanging Fruit</title>
    
    <link href="https://dor.ky/app-performance-low-hanging-fruit/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-25T12:38:49-00:00</updated>
    <id>https://dor.ky/app-performance-low-hanging-fruit/</id>
    <content type="html">&lt;p&gt;One of my favourite developers, &lt;a href=&quot;https://twitter.com/AndrewDelPrete&quot;&gt;Andrew Del Prete&lt;/a&gt; has written a new mini blog series on quick wins for performance and low hanging fruit changes that can be made to give you easy wins.&lt;/p&gt;
&lt;p&gt;You can find the first (and other five parts) over on the &lt;a href=&quot;http://www.learnperf.com/2017/01/02/app-performance-low-hanging-fruitpart-1-priorities/&quot;&gt;learnperf.com blog&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Overview of Apple&#39;s iCloud Security &amp; Encryption Features</title>
    
    <link href="https://dor.ky/overview-of-apples-icloud-security-encryption-features/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-24T12:33:13-00:00</updated>
    <id>https://dor.ky/overview-of-apples-icloud-security-encryption-features/</id>
    <content type="html">&lt;p&gt;A talk given at Blackhat conference this year explain how Apple ensure that their customer data is safe. You can &lt;a href=&quot;https://www.blackhat.com/docs/us-16/materials/us-16-Krstic.pdf&quot;&gt;download a PDF of the slides here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>All About Google&#39;s AMP</title>
    
    <link href="https://dor.ky/all-about-googles-amp/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-23T12:28:59-00:00</updated>
    <id>https://dor.ky/all-about-googles-amp/</id>
    <content type="html">&lt;p&gt;This is a really good overview of Google’s AMP project and how it came to be.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
  &lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;
    Breaking down AMP—the format, rules, and cache—from &lt;a href=&quot;https://twitter.com/adactio&quot;&gt;@adactio&lt;/a&gt;. &lt;a href=&quot;https://t.co/rX6AWoYJ8U&quot;&gt;https://t.co/rX6AWoYJ8U&lt;/a&gt;
  &lt;/p&gt;
  &lt;p&gt;
    — A Book Apart (@abookapart) &lt;a href=&quot;https://twitter.com/abookapart/status/845012282455347200&quot;&gt;March 23, 2017&lt;/a&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Magento SQL Profiler</title>
    
    <link href="https://dor.ky/magento-sql-profiler/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-22T12:27:30-00:00</updated>
    <id>https://dor.ky/magento-sql-profiler/</id>
    <content type="html">&lt;p&gt;I’d seen a tweet to Ben Marks this week which detailed an &lt;a href=&quot;https://github.com/ldusan84/LDusan_QueryTrace&quot;&gt;SQL profiler for Magento 1&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How Tube Stations Got Their Name</title>
    
    <link href="https://dor.ky/how-tube-stations-got-their-name/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-21T12:26:17-00:00</updated>
    <id>https://dor.ky/how-tube-stations-got-their-name/</id>
    <content type="html">&lt;p&gt;Pretty interesting post on how some of the more obscurely named stations &lt;a href=&quot;http://www.bbc.com/autos/story/20170208-how-tube-stations-got-their-hilarious-names&quot;&gt;got their names&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Android Install Older Version of Build Tools</title>
    
    <link href="https://dor.ky/android-install-older-version-of-build-tools/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-20T12:56:23-00:00</updated>
    <id>https://dor.ky/android-install-older-version-of-build-tools/</id>
    <content type="html">&lt;p&gt;If you need to install an older version of Android’s build tools, you can do so using the below. Search for the SDK version you want:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;$: android list sdk --all | grep -I tools&lt;/pre&gt;
&lt;p&gt;Which will then give you an indexed list of SDKs:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;1- Android SDK Tools, revision 25.2.5
   2- Android SDK Platform-tools, revision 25.0.4
   3- Android SDK Build-tools, revision 25.0.2
   4- Android SDK Build-tools, revision 25.0.1
   5- Android SDK Build-tools, revision 25
   6- Android SDK Build-tools, revision 24.0.3
   7- Android SDK Build-tools, revision 24.0.2
   8- Android SDK Build-tools, revision 24.0.1
   9- Android SDK Build-tools, revision 24
  10- Android SDK Build-tools, revision 23.0.3
  11- Android SDK Build-tools, revision 23.0.2
  12- Android SDK Build-tools, revision 23.0.1
  13- Android SDK Build-tools, revision 23 (Obsolete)
  14- Android SDK Build-tools, revision 22.0.1
  15- Android SDK Build-tools, revision 22 (Obsolete)
  16- Android SDK Build-tools, revision 21.1.2
  17- Android SDK Build-tools, revision 21.1.1 (Obsolete)
  18- Android SDK Build-tools, revision 21.1 (Obsolete)
  19- Android SDK Build-tools, revision 21.0.2 (Obsolete)
  20- Android SDK Build-tools, revision 21.0.1 (Obsolete)
  21- Android SDK Build-tools, revision 21 (Obsolete)
  22- Android SDK Build-tools, revision 20
  23- Android SDK Build-tools, revision 19.1
  24- Android SDK Build-tools, revision 19.0.3 (Obsolete)
  25- Android SDK Build-tools, revision 19.0.2 (Obsolete)
  26- Android SDK Build-tools, revision 19.0.1 (Obsolete)
  27- Android SDK Build-tools, revision 19 (Obsolete)
  28- Android SDK Build-tools, revision 18.1.1 (Obsolete)
  29- Android SDK Build-tools, revision 18.1 (Obsolete)
  30- Android SDK Build-tools, revision 18.0.1 (Obsolete)
  31- Android SDK Build-tools, revision 17 (Obsolete)&lt;/pre&gt;
&lt;p&gt;and then you can install a specific package with the ID:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;$: android update sdk -u -a -t 6&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/26016770/how-to-install-old-version-of-android-build-tools-from-command-line&quot;&gt;This blog post&lt;/a&gt; helped to discover the way to accomplish this.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Magento 2 Glossary</title>
    
    <link href="https://dor.ky/magento-2-glossary/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-19T10:57:17-00:00</updated>
    <id>https://dor.ky/magento-2-glossary/</id>
    <content type="html">&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
  &lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;
    Check &lt;a href=&quot;https://twitter.com/hashtag/magento2?src=hash&quot;&gt;#magento2&lt;/a&gt; glossary &amp;#8211; &lt;a href=&quot;https://t.co/e0mSvIpbvg&quot;&gt;https://t.co/e0mSvIpbvg&lt;/a&gt; and give us feedback.
  &lt;/p&gt;
  &lt;p&gt;
    — Max (@maksek_ua) &lt;a href=&quot;https://twitter.com/maksek_ua/status/843479724374482944&quot;&gt;March 19, 2017&lt;/a&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Pro Tip: Find All HP Printers on Your Local Network</title>
    
    <link href="https://dor.ky/pro-tip-find-all-hp-printers-on-your-local-network/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-18T09:08:18-00:00</updated>
    <id>https://dor.ky/pro-tip-find-all-hp-printers-on-your-local-network/</id>
    <content type="html">&lt;p&gt;Using nmap (installable with homebrew) you can run the following to get the IP addresses of all the HP printers on your local network:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true  &quot;&gt;nmap -v -A 192.168.0.\* | grep 9100&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Appcelerator Titanium &amp;#8211; Set Build Tools Version</title>
    
    <link href="https://dor.ky/appcelerator-titanium-set-build-tools-version/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-17T09:06:43-00:00</updated>
    <id>https://dor.ky/appcelerator-titanium-set-build-tools-version/</id>
    <content type="html">&lt;p&gt;If you have a newer version of build tools and need to fix the version currently in use, you can set the following:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;appc ti config android.buildTools.selectedVersion 23.0.3&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Git Tip: Display Contributions per User</title>
    
    <link href="https://dor.ky/git-tip-display-contributions-per-user/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-16T09:05:09-00:00</updated>
    <id>https://dor.ky/git-tip-display-contributions-per-user/</id>
    <content type="html">&lt;p&gt;You can use the following to display committer name and their contribution counts:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;git shortlog -sn&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Base64 Encode &amp; Decode on OSX</title>
    
    <link href="https://dor.ky/base64-encode-decode-on-osx/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-15T09:01:02-00:00</updated>
    <id>https://dor.ky/base64-encode-decode-on-osx/</id>
    <content type="html">&lt;p&gt;On OSX you can quickly base64 encode:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;base64 -in filename.txt &amp;gt; filename.b64&lt;/pre&gt;
&lt;p&gt;and decode files:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;base64 -D -in filename.b64 &amp;gt; filename.txt&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>AWS Updates Quickstart for Magento 2</title>
    
    <link href="https://dor.ky/aws-updates-quickstart-for-magento/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-14T08:58:45-00:00</updated>
    <id>https://dor.ky/aws-updates-quickstart-for-magento/</id>
    <content type="html">&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
  &lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;
    Try out our updated Quick Start for Magento 2.1.5 on the AWS Cloud &amp;#8211; with Amazon EFS &amp; Amazon ElastiCache! &lt;a href=&quot;https://t.co/Y81C9wAQQi&quot;&gt;https://t.co/Y81C9wAQQi&lt;/a&gt; &lt;a href=&quot;https://t.co/6b47n6TlRr&quot;&gt;pic.twitter.com/6b47n6TlRr&lt;/a&gt;
  &lt;/p&gt;
  &lt;p&gt;
    &amp;mdash; Amazon Web Services (@awscloud) &lt;a href=&quot;https://twitter.com/awscloud/status/843929039911895040&quot;&gt;March 20, 2017&lt;/a&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>MET Police Using Indian Hacking Agency</title>
    
    <link href="https://dor.ky/met-police-using-indian-hacking-agency/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-12T08:51:55-00:00</updated>
    <id>https://dor.ky/met-police-using-indian-hacking-agency/</id>
    <content type="html">&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
  &lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;
    .&lt;a href=&quot;https://twitter.com/metpoliceuk&quot;&gt;@metpoliceuk&lt;/a&gt; used an Indian agency to hack activists and journalists in UK &amp;#8211; then shredded the evidence. Just wow. &lt;a href=&quot;https://t.co/g0Y4RD2SOn&quot;&gt;https://t.co/g0Y4RD2SOn&lt;/a&gt;
  &lt;/p&gt;
  &lt;p&gt;
    &amp;mdash; Matthew Butcher (@matthew1butcher) &lt;a href=&quot;https://twitter.com/matthew1butcher/status/844228677353259008&quot;&gt;March 21, 2017&lt;/a&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Quick Way of Remembering PHP Needle/Haystack Order</title>
    
    <link href="https://dor.ky/quick-way-of-remembering-php-needlehaystack-order/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-10T08:48:16-00:00</updated>
    <id>https://dor.ky/quick-way-of-remembering-php-needlehaystack-order/</id>
    <content type="html">&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
  &lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;
    Friendly reminder → in PHP, string functions are haystack/needle, array functions are needle/haystack (except array_filter).
  &lt;/p&gt;
  &lt;p&gt;
    — assertchris (@assertchris) &lt;a href=&quot;https://twitter.com/assertchris/status/844245824242704384&quot;&gt;March 21, 2017&lt;/a&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>We Made the Whole Company Serverless</title>
    
    <link href="https://dor.ky/we-made-the-whole-company-serverless/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-09T08:46:33-00:00</updated>
    <id>https://dor.ky/we-made-the-whole-company-serverless/</id>
    <content type="html">&lt;p&gt;Interesting post about taking a &lt;a href=&quot;https://blog.cloudsploit.com/we-made-the-whole-company-serverless-5a91c27cd8c4&quot;&gt;server-less approach to running a cloud service&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Magento 2 Slow During Development</title>
    
    <link href="https://dor.ky/magento-2-slow-during-development/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-08T08:45:00-00:00</updated>
    <id>https://dor.ky/magento-2-slow-during-development/</id>
    <content type="html">&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
  &lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;
    If you&#39;ve been complaining about M2 being slow during development: read this! Awesome summary! &lt;a href=&quot;https://t.co/QiZ48WlVz9&quot;&gt;https://t.co/QiZ48WlVz9&lt;/a&gt;
  &lt;/p&gt;
  &lt;p&gt;
    — Anna Völkl (@rescueAnn) &lt;a href=&quot;https://twitter.com/rescueAnn/status/843576731567083520&quot;&gt;March 19, 2017&lt;/a&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Quickly Generate SSL Key &amp;#038; CSR</title>
    
    <link href="https://dor.ky/quickly-generate-ssl-key-csr/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-07T11:10:12-00:00</updated>
    <id>https://dor.ky/quickly-generate-ssl-key-csr/</id>
    <content type="html">&lt;p&gt;Quickly generate a new SSH keypair and then a CSR:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;openssl genrsa -out private.key 4096
openssl req -new -key private.key -out private.csr
&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Quickly Start New Projects From Git Repo</title>
    
    <link href="https://dor.ky/quickly-start-new-projects-from-git-repo/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-06T10:00:04-00:00</updated>
    <id>https://dor.ky/quickly-start-new-projects-from-git-repo/</id>
    <content type="html">&lt;p&gt;Found this piece of code a while ago which is useful if you want to start projects from a skeleton repo or similar starting point.&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;mkdir new-laravel-project
cd new-laravel-project
git init
git fetch --depth=1 -n https://github.com/laravel/laravel
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m &quot;Initial Commit&quot;)
&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Installing Mailhog for Use with Laravel Valet</title>
    
    <link href="https://dor.ky/installing-mailhog-for-use-with-laravel-valet/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-05T15:07:03-00:00</updated>
    <id>https://dor.ky/installing-mailhog-for-use-with-laravel-valet/</id>
    <content type="html">&lt;p&gt;Really &lt;a href=&quot;https://pascalbaljetmedia.com/en/blog/setup-mailhog-with-laravel-valet&quot;&gt;decent article&lt;/a&gt; on how to use a homebrew installed Mailhog for Laravel Valet.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Add a Git alias to List Git Aliases</title>
    
    <link href="https://dor.ky/add-a-git-alias-to-list-git-aliases/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-03T17:42:44-00:00</updated>
    <id>https://dor.ky/add-a-git-alias-to-list-git-aliases/</id>
    <content type="html">&lt;pre class=&quot;lang:sh decode:true &quot;&gt;git config --global alias.alias &quot;config --get-regexp ^alias\.&quot;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>OSX &amp;#8211; Disable Gatekeeper to Allow Installation of Unsigned Apps</title>
    
    <link href="https://dor.ky/osx-disable-gatekeeper-to-allow-installation-of-unsigned-apps/" rel="alternate" type="text/html"/>
    
    <updated>2017-03-02T17:42:07-00:00</updated>
    <id>https://dor.ky/osx-disable-gatekeeper-to-allow-installation-of-unsigned-apps/</id>
    <content type="html">&lt;p&gt;Run this in your terminal to allow the option of selecting install from anywhere:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;sudo spctl --master-disable&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Use nano in Docker containers</title>
    
    <link href="https://dor.ky/use-nano-in-docker-containers/" rel="alternate" type="text/html"/>
    
    <updated>2016-11-20T10:05:54-00:00</updated>
    <id>https://dor.ky/use-nano-in-docker-containers/</id>
    <content type="html">&lt;p&gt;If for some reason you find yourself needing to use `nano` in a Docker container, you can set the terminal type and then you’ll be able to use it. Say for example you ran `bash` with the exec command, you can then run:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;export TERM=xterm-256color&lt;/pre&gt;
&lt;p&gt;and it’ll allow you to use the terminal as normal for nano/clear etc.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>teleconsole</title>
    
    <link href="https://dor.ky/teleconsole/" rel="alternate" type="text/html"/>
    
    <updated>2016-10-13T21:02:35-00:00</updated>
    <id>https://dor.ky/teleconsole/</id>
    <content type="html">&lt;p&gt;This is a nifty little app that will allow you to share a terminal console with others. It’s called &lt;a href=&quot;https://www.teleconsole.com/&quot;&gt;teleconsole&lt;/a&gt;, check it out if you have a use case.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Set keyfile to use for SFTP</title>
    
    <link href="https://dor.ky/set-keyfile-to-use-for-sftp/" rel="alternate" type="text/html"/>
    
    <updated>2016-09-16T09:28:02-00:00</updated>
    <id>https://dor.ky/set-keyfile-to-use-for-sftp/</id>
    <content type="html">&lt;p&gt;If you want to specify the keyfile used for an SFTP connection, you can use the following:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true&quot;&gt;sftp -i /path/to/private/keyfile user@machine1:/path/to/file user@machine2:/path/to/file&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Vagrant SSL Error Fix</title>
    
    <link href="https://dor.ky/vagrant-ssl-error-fix/" rel="alternate" type="text/html"/>
    
    <updated>2016-09-12T11:02:38-00:00</updated>
    <id>https://dor.ky/vagrant-ssl-error-fix/</id>
    <content type="html">&lt;p&gt;Minor issue this morning where Vagrant wouldn’t fetch a box completely, turns out that the local cache looked corrupted and you would get this error:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;SSL read: error:00000000:lib(0):func(0):reason(0), errno 60&lt;/pre&gt;
&lt;p&gt;you can force it to refetch entirely, by using the command:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;vagrant box add box/name -c&lt;/pre&gt;
&lt;p class=&quot;p1&quot;&gt;
  then run your &lt;code&gt;vagrant up&lt;/code&gt; as usual and it should work.
&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Auto Deploy Couscous.io Docs to Laravel Forge</title>
    
    <link href="https://dor.ky/auto-deploy-couscous-io-docs-to-laravel-forge/" rel="alternate" type="text/html"/>
    
    <updated>2016-09-09T12:28:13-00:00</updated>
    <id>https://dor.ky/auto-deploy-couscous-io-docs-to-laravel-forge/</id>
    <content type="html">&lt;p&gt;If you use &lt;a href=&quot;http://couscous.io/&quot;&gt;couscous.io&lt;/a&gt; to generate documentation and Laravel Forge, you can set up auto deployment and publishing quite easily. Setup the site in Forge, making sure you have a composer.json and an empty public directory in your repo.&lt;/p&gt;
&lt;p&gt;You can then use this deploy script to build, move and publish your changes automatically after you’ve added a webhook too:&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Titanium Appcelerator: Install Specific SDK Version</title>
    
    <link href="https://dor.ky/titanium-appcelerator-install-specific-sdk-version/" rel="alternate" type="text/html"/>
    
    <updated>2016-07-07T16:09:18-00:00</updated>
    <id>https://dor.ky/titanium-appcelerator-install-specific-sdk-version/</id>
    <content type="html">&lt;p&gt;If you need to install a specific version of Titanium’s SDKs, use the following command:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true&quot;&gt;appc ti sdk install 5.2.0.GA&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Clone a git repo using a specific SSH private key</title>
    
    <link href="https://dor.ky/clone-a-git-repo-using-a-specific-ssh-private-key/" rel="alternate" type="text/html"/>
    
    <updated>2016-05-22T10:00:48-00:00</updated>
    <id>https://dor.ky/clone-a-git-repo-using-a-specific-ssh-private-key/</id>
    <content type="html">&lt;p&gt;If you wish to clone a repo using a set private key, you can use the following syntax to do just that and it won’t add the private key to your usual SSH settings:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;ssh-agent bash -c &#39;ssh-add private.key; git clone git@server.com:user/repo.git&#39;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Generating Public &amp;#038; Private Keys Using PHPSECLIB</title>
    
    <link href="https://dor.ky/generating-public-private-keys-using-phpseclib/" rel="alternate" type="text/html"/>
    
    <updated>2016-05-21T17:23:02-00:00</updated>
    <id>https://dor.ky/generating-public-private-keys-using-phpseclib/</id>
    <content type="html">&lt;p&gt;A few tasks that I’ve been working on this weekend have needed public/private key pairs. The very useful &lt;a href=&quot;https://github.com/phpseclib/phpseclib&quot; target=&quot;_blank&quot;&gt;phpseclib&lt;/a&gt; library provides the tools that you need to generate these within your application.&lt;/p&gt;
&lt;pre class=&quot;lang:php decode:true  &quot;&gt;// Get a new RSA object and set the type, hash and comment
$rsa = new RSA;
$rsa-&amp;gt;setPublicKeyFormat(phpseclib\Crypt\RSA::PUBLIC_FORMAT_OPENSSH);
$rsa-&amp;gt;setHash(&#39;sha256&#39;);
$rsa-&amp;gt;setComment(&#39;user@seccheck&#39;);

// Actually generate the key, change 4096 for the desired number of bytes
$keys 		= $rsa-&amp;gt;createKey(4096);
$keyPrivate	= $keys[&quot;privatekey&quot;];
$keyPublic	= $keys[&quot;publickey&quot;];

// Get the fingerprint for this key
$rsa-&amp;gt;loadKey($keyPrivate); 
$keyFingerprint = $rsa-&amp;gt;getPublicKeyFingerprint();&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Embed Github files Gist Style</title>
    
    <link href="https://dor.ky/embed-github-files-gist-style/" rel="alternate" type="text/html"/>
    
    <updated>2016-05-20T08:27:28-00:00</updated>
    <id>https://dor.ky/embed-github-files-gist-style/</id>
    <content type="html">&lt;p&gt;If you’ve ever wanted to embed a Github file into your site, in the same style that Gist does, there’s a decent app over at &lt;a href=&quot;http://gist-it.appspot.com/&quot; target=&quot;_blank&quot;&gt;http://gist-it.appspot.com&lt;/a&gt; that will do just that.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Searching the Internet for Devices</title>
    
    <link href="https://dor.ky/searching-the-internet-for-devices/" rel="alternate" type="text/html"/>
    
    <updated>2016-05-18T08:43:46-00:00</updated>
    <id>https://dor.ky/searching-the-internet-for-devices/</id>
    <content type="html">&lt;p&gt;This is a pretty nifty service I come across a few days ago. It’s called &lt;a href=&quot;https://www.shodan.io/&quot; target=&quot;_blank&quot;&gt;Shodan&lt;/a&gt; and searches then indexes internet connected devices around the world.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Using UUIDs in Laravel Projects</title>
    
    <link href="https://dor.ky/using-uuids-in-laravel-projects/" rel="alternate" type="text/html"/>
    
    <updated>2016-05-17T09:02:00-00:00</updated>
    <id>https://dor.ky/using-uuids-in-laravel-projects/</id>
    <content type="html">&lt;p&gt;There’s a good article on using UUIDs instead on integer IDs on on Medium by Steve Azzopardi. Head over to &lt;a href=&quot;https://medium.com/@steveazz/setting-up-uuids-in-laravel-5-552412db2088&quot;&gt;“Setting up UUIDs in Laravel” on Medium&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Chrome Casting Audio from Mac OSX</title>
    
    <link href="https://dor.ky/chrome-casting-audio-from-mac-osx/" rel="alternate" type="text/html"/>
    
    <updated>2016-05-16T20:17:11-00:00</updated>
    <id>https://dor.ky/chrome-casting-audio-from-mac-osx/</id>
    <content type="html">&lt;p&gt;If you’re a Mac OSX user and would like to send your audio over to a Chromecast device (ie, playing iTunes or Spotify) then there’s a fantastic project called soundcast which will allow you to do just that. You can find the project over on Github at &lt;a href=&quot;https://github.com/andresgottlieb/soundcast&quot; target=&quot;_blank&quot;&gt;https://github.com/andresgottlieb/soundcast&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Export Files from iTunes Playlist</title>
    
    <link href="https://dor.ky/export-files-from-itunes-playlist/" rel="alternate" type="text/html"/>
    
    <updated>2016-05-08T11:21:32-00:00</updated>
    <id>https://dor.ky/export-files-from-itunes-playlist/</id>
    <content type="html">&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
  &lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;
    Handy tip: You can drag/drop files from an &lt;a href=&quot;https://twitter.com/hashtag/iTunes?src=hash&quot;&gt;#iTunes&lt;/a&gt; playlist into a mount device on OSX. Useful for portable devices. &lt;a href=&quot;https://twitter.com/hashtag/osx?src=hash&quot;&gt;#osx&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/mac?src=hash&quot;&gt;#mac&lt;/a&gt;
  &lt;/p&gt;
  &lt;p&gt;
    &amp;mdash; Scott Wilcox (@ssx) &lt;a href=&quot;https://twitter.com/ssx/status/729254017398935552&quot;&gt;May 8, 2016&lt;/a&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>The .well-known Directory on Webservers</title>
    
    <link href="https://dor.ky/the-well-known-directory-on-webservers/" rel="alternate" type="text/html"/>
    
    <updated>2016-03-20T16:58:06-00:00</updated>
    <id>https://dor.ky/the-well-known-directory-on-webservers/</id>
    <content type="html">&lt;p&gt;If you’ve often seen things looking for a directory called .well-known on your HTTP server access logs, you’d be like me if you were surprised to know there is actually quite a lot more to that directory name. It provides information about services and a whole bunch more. You can read a lot more on &lt;a href=&quot;https://ma.ttias.be/well-known-directory-webservers-aka-rfc-5785/&quot; target=&quot;_blank&quot;&gt;Mattias’s blog post about it&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Linux Server: Send Email on File Change</title>
    
    <link href="https://dor.ky/linux-server-send-email-on-file-change/" rel="alternate" type="text/html"/>
    
    <updated>2016-03-14T18:00:45-00:00</updated>
    <id>https://dor.ky/linux-server-send-email-on-file-change/</id>
    <content type="html">&lt;p&gt;This script will send an email when a file changes in the given path. Can’t remember where I picked this up from but it’s useful to have when you need to debug something that writes files.&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;#!/bin/sh
#
# Monitor file $1 for changes
# Send an alert emai to $2 if file $1 changes
# usage: file_change_mail_alert.sh /var/log/messages your.name@domain.com
#

if [ -z &quot;$2&quot; ]; then
echo &quot;Usage: file_change_mail_alert.sh &quot;
exit 1
fi

#if a inotifywait for this file is already running
if [ $(ps aux | grep inotifywait | grep -c &quot;$1&quot; ) -gt &#39;0&#39; ]; then
	echo &quot;A process monitoring the file $1 is already running: $(ps aux | grep inotifywait | grep &quot;$1&quot; )&quot;;
	exit 1;
fi

#if inotifywait exists
type -P inotifywait &amp;&amp;gt;/dev/null || { echo &quot;Error: This script requires inotifywait(http://wiki.github.com/rvoicilas/inotify-tools/) .... apt-get install inotify-tools ... &quot; &amp;gt;&amp;2; exit 1; }

#if the file exists
# if [ -f $1 ]; then

echo &quot;Monitoring file $1 for changes - sending alerts to $2&quot;

while inotifywait -e modify -e attrib -e move -e delete $1 -o /root/audit.log; do
	sleep 1
	
	# changes=&quot;$(tail -n5 $1)&quot;
	
	changes=&quot;$(cat /root/audit.log)&quot;
		echo &quot;The following change occurred in the file $1 : $changes&quot; | mail -s &quot;Change in $1&quot; $2
		rm /root/audit.log
		touch /root/audit.log		
	done
else
	echo &quot;Error: File $1 not found&quot;
fi
&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Outbound FTP Issues with Virtualmin</title>
    
    <link href="https://dor.ky/outbound-ftp-issues-with-virtualmin/" rel="alternate" type="text/html"/>
    
    <updated>2016-03-12T18:00:16-00:00</updated>
    <id>https://dor.ky/outbound-ftp-issues-with-virtualmin/</id>
    <content type="html">&lt;p&gt;If you’re a Virtualmin user and use the iptables based firewall, you may have issues with outbound FTP working. The FTP connection can often be made, but then stalls at receiving data.&lt;/p&gt;
&lt;p&gt;You can fix this by adding the &lt;strong&gt;nf_conntrack_ftp&lt;/strong&gt; module to your machine. As root or sudo bash, create the following file:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true&quot;&gt;/etc/modules-load.d/nf_conntrack_ftp.conf&lt;/pre&gt;
&lt;p&gt;and within that file put:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;modprobe nf_conntrack_ftp&lt;/pre&gt;
&lt;p&gt;This will make sure that module gets loaded after each boot and fix your connection issue.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Making Local Development Faster with Caches for NPM &amp;#038; Composer (Part Two: Composer)</title>
    
    <link href="https://dor.ky/making-local-development-faster-with-caches-for-npm-composer-part-two-composer/" rel="alternate" type="text/html"/>
    
    <updated>2016-03-11T18:00:41-00:00</updated>
    <id>https://dor.ky/making-local-development-faster-with-caches-for-npm-composer-part-two-composer/</id>
    <content type="html">&lt;p&gt;If you’re a heavy PHP user, you’ll most likely be using &lt;a href=&quot;http://packagist.org/&quot;&gt;packagist.org&lt;/a&gt; quite a bit during your development cycles. A quick win in speeding this up is using a local cache for Packagist which means you’re only downloading across your local network instead of across the Internet.&lt;/p&gt;
&lt;p&gt;You can run a local &lt;a href=&quot;https://toranproxy.com/&quot; target=&quot;_blank&quot;&gt;toran proxy&lt;/a&gt; instance by running this command:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;docker run --name toran-proxy -d -p 82:80 -v /opt/toran-proxy:/data/toran-proxy -e &quot;TORAN_CRON_TIMER=half&quot; -e &quot;TORAN_TOKEN_GITHUB=8ba3e80d61fb&quot; -e &quot;TORAN_PHP_TIMEZONE=Europe/London&quot; -e &quot;TORAN_HOST=toran.local:82&quot; cedvan/toran-proxy:1.1.7-1&lt;/pre&gt;
&lt;p&gt;We can break this down a little bit. The volume mount means that we have persistence with our cache and settings. We use port 82 and the hostname of toran.local. This means that we can add the following the to our projects composer.json:&lt;/p&gt;
&lt;pre class=&quot;lang:js decode:true &quot;&gt;&quot;repositories&quot;: [
    {&quot;type&quot;: &quot;composer&quot;, &quot;url&quot;: &quot;http://toran.local:82/repo/packagist/&quot;},
    {&quot;packagist&quot;: false}
]&lt;/pre&gt;
&lt;p&gt;Your local composer will now begin to use your &lt;a href=&quot;https://toranproxy.com/&quot; target=&quot;_blank&quot;&gt;toran proxy&lt;/a&gt; instance. You can read more information about the Docker image used here over at the &lt;a href=&quot;https://github.com/cedvan/docker-toran-proxy&quot; target=&quot;_blank&quot;&gt;Github repo&lt;/a&gt; or on the &lt;a href=&quot;https://hub.docker.com/r/cedvan/toran-proxy/&quot; target=&quot;_blank&quot;&gt;Docker hub page&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;You can read the first part of this series detailing an &lt;a href=&quot;https://dor.ky/making-local-development-faster-with-caches-for-npm-composer-part-one-npm/&quot; target=&quot;_blank&quot;&gt;NPM cache here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Google Doc&#39;s Will Support Save as ePub</title>
    
    <link href="https://dor.ky/google-docs-will-support-save-as-epub/" rel="alternate" type="text/html"/>
    
    <updated>2016-03-08T18:03:19-00:00</updated>
    <id>https://dor.ky/google-docs-will-support-save-as-epub/</id>
    <content type="html">&lt;p&gt;This is a nice feature being added to Google docs that will allow you to save your document as an ePub file. You can read more over on the &lt;a href=&quot;http://googleappsupdates.blogspot.co.uk/2016/03/export-google-docs-files-as-epub.html&quot; target=&quot;_blank&quot;&gt;Google Apps Blog&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>PHP UK Postcode Manipulation Library</title>
    
    <link href="https://dor.ky/php-uk-postcode-manipulation-library/" rel="alternate" type="text/html"/>
    
    <updated>2016-03-04T18:00:13-00:00</updated>
    <id>https://dor.ky/php-uk-postcode-manipulation-library/</id>
    <content type="html">&lt;p&gt;I’ve added a composer installable package for the excellent UK postcode library written by &lt;a href=&quot;http://stephenmorley.org/&quot; target=&quot;_blank&quot;&gt;Stephen Morley&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can find the original package &lt;a href=&quot;http://code.stephenmorley.org/php/handling-uk-postcodes/&quot; target=&quot;_blank&quot;&gt;over on his site&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel &amp;#038; Lumen: Return Correct Error Responses for Requests</title>
    
    <link href="https://dor.ky/laravel-lumen-return-correct-error-responses-for-requests/" rel="alternate" type="text/html"/>
    
    <updated>2016-03-03T18:00:05-00:00</updated>
    <id>https://dor.ky/laravel-lumen-return-correct-error-responses-for-requests/</id>
    <content type="html">&lt;p&gt;I’ve seen a few pieces of API code dotted around the web recently where people have written simple JSON APIs but their error handling still returns HTML instead of JSON for 404 errors and the likes. This is pretty simple to solve with Laravel or Lumen and easily testable too. The cleanest way I’ve seen of handling this was written by Paul Redmond in his book &lt;a href=&quot;https://leanpub.com/lumen-apis&quot; target=&quot;_blank&quot;&gt;‘Writing APIs with Lumen’&lt;/a&gt; which you can purchase on &lt;a href=&quot;https://leanpub.com/lumen-apis&quot; target=&quot;_blank&quot;&gt;Leanpub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In your error handler, typically located at app/Exceptions/Handler.php, you’ll need to add a check for wantsJson() on the Request object, like this:&lt;/p&gt;
&lt;pre class=&quot;lang:php decode:true &quot;&gt;&amp;lt;?php

namespace App\Exceptions;

use Exception;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpFoundation\Response;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        AuthorizationException::class,
        HttpException::class,
        ModelNotFoundException::class,
        ValidationException::class,
    ];

    /**
     * Report or log an exception.
     *
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
     *
     * @param  \Exception  $e
     * @return void
     */
    public function report(Exception $e)
    {
        parent::report($e);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $e
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $e)
    {
        if ($request-&amp;gt;wantsJson()) {
            $response = [
                &#39;message&#39; =&amp;gt; (string) $e-&amp;gt;getMessage(),
                &#39;status&#39; =&amp;gt; 400
            ];

            if ($e instanceof HttpException) {
                $response[&#39;message&#39;] = Response::$statusTexts[$e-&amp;gt;getStatusCode()];
                $response[&#39;status&#39;] = $e-&amp;gt;getStatusCode();
            } else if ($e instanceof ModelNotFoundException) {
                $response[&#39;message&#39;] = Response::$statusTexts[Response::HTTP_NOT_FOUND];
                $response[&#39;status&#39;] = Response::HTTP_NOT_FOUND;
            }

            if ($this-&amp;gt;isDebugMode()) {
                $response[&#39;debug&#39;] = [
                    &#39;exception&#39; =&amp;gt; get_class($e),
                    &#39;trace&#39; =&amp;gt; $e-&amp;gt;getTrace()
                ];
            }

            return response()-&amp;gt;json([&#39;error&#39; =&amp;gt; $response], $response[&#39;status&#39;]);
        }

        return parent::render($request, $e);
    }

    /**
     * Determine if the application is in debug mode.
     *
     * @return Boolean
     */
    public function isDebugMode()
    {
        return (boolean) env(&#39;APP_DEBUG&#39;);
    }
}&lt;/pre&gt;
&lt;p&gt;Pretty simple and effective, you can handle more cases within your handler as well, but that’s enough to illustrate the idea. You can test the above is working by using something similar to this test:&lt;/p&gt;
&lt;pre class=&quot;lang:php decode:true&quot;&gt;class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {

        $this-&amp;gt;json(&quot;get&quot;, &quot;/page-that-does-not-exist&quot;)
             -&amp;gt;seeJsonStructure([
                 &quot;error&quot;
             ]);

    }
}
&lt;/pre&gt;
&lt;p&gt;A quick and simple tip, but one that seems to be overlooked often.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Making Local Development Faster with Caches for NPM &amp;#038; Composer (Part One: NPM)</title>
    
    <link href="https://dor.ky/making-local-development-faster-with-caches-for-npm-composer-part-one-npm/" rel="alternate" type="text/html"/>
    
    <updated>2016-03-02T17:00:12-00:00</updated>
    <id>https://dor.ky/making-local-development-faster-with-caches-for-npm-composer-part-one-npm/</id>
    <content type="html">&lt;p&gt;This is the first post in a two part series detailing how you can use Docker to run local caches of both remote NPM resources and composer packages.&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;docker pull keyvanfatehi/sinopia&lt;/pre&gt;
&lt;p&gt;After the image has been pulled down, you can run it and map to a port using the following syntax:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;docker run -p 81:4873 keyvanfatehi/sinopia&lt;/pre&gt;
&lt;p&gt;This will run sinopia and bind the external interface to port 81. There is a fair few configuration options that you can specify, I’d recommend getting a copy of the configuration file then mounting that as a volume.&lt;/p&gt;
&lt;p&gt;Next, at the top of the screen, it’ll give you the two commands to make your client version of NPM connect to your new shiny cache, it’ll be something similar to:&lt;/p&gt;
&lt;img class=&quot;alignnone size-medium wp-image-1369&quot; src=&quot;https://dor.ky/assets/images/old_content/Screenshot-2016-03-02-11.42.51-300x104.png&quot; alt=&quot;Screenshot 2016-03-02 11.42.51&quot;&gt;
&lt;hr&gt;
&lt;p&gt;If you run those two commands, it’ll set your client to use your new cache and you’re good to go.&lt;/p&gt;
&lt;p&gt;The following links are useful reference for this post:&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;https://github.com/rlidwka/sinopia&quot;&gt;https://github.com/rlidwka/sinopia&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;](&lt;a href=&quot;https://github.com/rlidwka/sinopia&quot;&gt;https://github.com/rlidwka/sinopia&lt;/a&gt;) [&lt;a href=&quot;https://hub.docker.com/r/keyvanfatehi/sinopia/&quot;&gt;https://hub.docker.com/r/keyvanfatehi/sinopia/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;](&lt;a href=&quot;https://hub.docker.com/r/keyvanfatehi/sinopia/&quot;&gt;https://hub.docker.com/r/keyvanfatehi/sinopia/&lt;/a&gt;) [&lt;a href=&quot;https://github.com/rlidwka/sinopia#using-private-packages&quot;&gt;https://github.com/rlidwka/sinopia#using-private-packages&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;](&lt;a href=&quot;https://github.com/rlidwka/sinopia#using-private-packages&quot;&gt;https://github.com/rlidwka/sinopia#using-private-packages&lt;/a&gt;) &lt;a href=&quot;https://blog.dylants.com/2014/05/10/creating-a-private-npm-registry-with-sinopia/&quot;&gt;https://blog.dylants.com/2014/05/10/creating-a-private-npm-registry-with-sinopia/&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>bcrypt Passwords for WordPress</title>
    
    <link href="https://dor.ky/bcrypt-passwords-for-wordpress/" rel="alternate" type="text/html"/>
    
    <updated>2016-03-01T18:35:52-00:00</updated>
    <id>https://dor.ky/bcrypt-passwords-for-wordpress/</id>
    <content type="html">&lt;p&gt;Great development from the Roots team to make WordPress use bcrypt for it’s password hashing. You can read more on their &lt;a href=&quot;https://roots.io/improving-wordpress-passwords-security/&quot; target=&quot;_blank&quot;&gt;blog post here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>MacOS Sierra Asking for SSH Passphrase</title>
    
    <link href="https://dor.ky/macos-sierra-asking-for-ssh-passphrase/" rel="alternate" type="text/html"/>
    
    <updated>2016-03-01T08:59:47-00:00</updated>
    <id>https://dor.ky/macos-sierra-asking-for-ssh-passphrase/</id>
    <content type="html">&lt;p&gt;There’s a recent change in the handling of SSH keys in MacOS Sierra that means you need to enter your passphrase each time a key is required. There’s &lt;a href=&quot;https://openradar.appspot.com/27348363&quot;&gt;an open Radar issue about it&lt;/a&gt; and it’s intended behaviour now.&lt;/p&gt;
&lt;p&gt;You can work around it by implementing one of the solutions at the links below, I personally went with adding:&lt;/p&gt;
&lt;pre class=&quot;lang:sh decode:true &quot;&gt;ssh-add -A 2&amp;gt;/dev/null;&lt;/pre&gt;
&lt;p&gt;into my .zshrc file and that solved it for me (or .bash_rc if you use bash).&lt;/p&gt;
&lt;p&gt;More information and solutions can be found at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://superuser.com/questions/1127067/macos-keeps-asking-my-ssh-passphrase-since-i-updated-to-sierra&quot;&gt;http://superuser.com/questions/1127067/macos-keeps-asking-my-ssh-passphrase-since-i-updated-to-sierra&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://apple.stackexchange.com/questions/254468/macos-sierra-doesn-t-seem-to-remember-ssh-keys-between-reboots&quot;&gt;http://apple.stackexchange.com/questions/254468/macos-sierra-doesn-t-seem-to-remember-ssh-keys-between-reboots&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Anbu: Laravel Profiling Tool</title>
    
    <link href="https://dor.ky/anbu-laravel-profiling-tool/" rel="alternate" type="text/html"/>
    
    <updated>2016-02-27T16:06:41-00:00</updated>
    <id>https://dor.ky/anbu-laravel-profiling-tool/</id>
    <content type="html">&lt;p&gt;If you’re a Laravel user and you’ve been looking for something to profile your application, try &lt;a href=&quot;https://anbu.io/&quot; target=&quot;_blank&quot;&gt;Anbu&lt;/a&gt;. It’s created by a friend, &lt;a href=&quot;https://twitter.com/daylerees&quot; target=&quot;_blank&quot;&gt;Dayle Rees&lt;/a&gt; and is currently in early beta but would be great for you to try and help out testing.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel Blade Stacks</title>
    
    <link href="https://dor.ky/laravel-blade-stacks/" rel="alternate" type="text/html"/>
    
    <updated>2016-02-25T18:06:22-00:00</updated>
    <id>https://dor.ky/laravel-blade-stacks/</id>
    <content type="html">&lt;p&gt;One thing that I often forget about is a nice feature in Laravel that allows you to push scripts or other blocks of code into another part of your templates, so for example:&lt;/p&gt;
&lt;pre class=&quot;lang:php decode:true&quot;&gt;@push(&#39;scripts&#39;)
    &amp;lt;script src=&quot;/example.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
@endpush
&lt;/pre&gt;
&lt;p&gt;You can do this multiple times and each one will be pushed on to the stack, when you’re ready to dump and display them, you can dump to view using @stack:&lt;/p&gt;
&lt;pre class=&quot;lang:php decode:true  &quot;&gt;&amp;lt;head&amp;gt;
    &amp;lt;!-- Head Contents --&amp;gt;

    @stack(&#39;scripts&#39;)
&amp;lt;/head&amp;gt;&lt;/pre&gt;
&lt;p&gt;Nothing ground breaking here, but incredibly useful. You can read more about it on the &lt;a href=&quot;https://laravel.com/docs/5.2/blade#stacks&quot; target=&quot;_blank&quot;&gt;Laravel documentation&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How do bank payments work?</title>
    
    <link href="https://dor.ky/how-do-bank-payments-work/" rel="alternate" type="text/html"/>
    
    <updated>2016-02-23T13:16:50-00:00</updated>
    <id>https://dor.ky/how-do-bank-payments-work/</id>
    <content type="html">&lt;p&gt;This was a pretty interesting read on &lt;a href=&quot;https://getmondo.co.uk/blog/2016/01/20/how-do-bank-payments-work/&quot; target=&quot;_blank&quot;&gt;how bank payments work&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Phan by Etsy &amp;#8211; PHP7 Based Static Analysis</title>
    
    <link href="https://dor.ky/phan-by-etsy-php7-based-static-analysis/" rel="alternate" type="text/html"/>
    
    <updated>2016-02-20T17:01:57-00:00</updated>
    <id>https://dor.ky/phan-by-etsy-php7-based-static-analysis/</id>
    <content type="html">&lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;
  Liking &lt;a href=&quot;https://github.com/etsy/phan&quot;&gt;Phan&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/Etsy&quot;&gt;@etsy&lt;/a&gt; for static analysis. PHP7 based, works well.
&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Approaches to Testing</title>
    
    <link href="https://dor.ky/approaches-to-testing/" rel="alternate" type="text/html"/>
    
    <updated>2016-02-20T08:33:18-00:00</updated>
    <id>https://dor.ky/approaches-to-testing/</id>
    <content type="html">&lt;p&gt;I came across this blog post this week which details approaches to testing, check it out:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://codingitwrong.com/2016/02/08/approaches-to-testing-a-survey.html&quot; target=&quot;_blank&quot;&gt;http://codingitwrong.com/2016/02/08/approaches-to-testing-a-survey.html&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Inspecting SQLite Databases in Appcelerator Titanium Projects</title>
    
    <link href="https://dor.ky/inspecting-sqlite-databases-in-appcelerator-titanium-projects/" rel="alternate" type="text/html"/>
    
    <updated>2016-01-23T11:35:58-00:00</updated>
    <id>https://dor.ky/inspecting-sqlite-databases-in-appcelerator-titanium-projects/</id>
    <content type="html">&lt;p&gt;If you’re using SQLite for your project and you’d like to query the database directly. For Android based devices or emulators, you can do the following:&lt;/p&gt;
&lt;p&gt;You’ll need to remember your database name, if you’re using commonJS, you can do something similar to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;exports.getDatabase = function() {
    return Ti.Database.open(&#39;app.db&#39;);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, find out what devices you have connected using &lt;code&gt;adb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;adb devices
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will return a list similar to this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;List of devices attached 
10.0.0.2:5555    device
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, use the ADB shell command to boot into the device:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;adb -s 10.0.0.2:5555 shell
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will drop you into a shell on the device. Next, find the database file. In the first code snippet here, you can see our database name is &lt;code&gt;app.db&lt;/code&gt;, so we’ll use a combination of find and grep to find the file on the device:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /; find * | grep app.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this will return the SQLite file and it’s journal, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@vbox86p:/ # cd /; find * | grep app.db
data/data/com.example.audit/databases/app.db
data/data/com.example.audit/databases/app.db-journal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can use the CLI tool to open the database, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sqlite3 data/data/com.example.audit/databases/app.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you’ll be dropped into the CLI tool. You can get a list of tables by using &lt;code&gt;.tables&lt;/code&gt; and exit the program via &lt;code&gt;.quit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The reference for this post came from this &lt;a href=&quot;http://tonylukasavage.com/blog/2013/04/08/inspecting-sqlite-databases-on-android-and-ios/&quot;&gt;wonderful blog post&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Virtualmin Migrated Site Error &#39;AuthGroupFile&#39;</title>
    
    <link href="https://dor.ky/virtualmin-migrated-site-error-authgroupfile/" rel="alternate" type="text/html"/>
    
    <updated>2016-01-19T19:37:21-00:00</updated>
    <id>https://dor.ky/virtualmin-migrated-site-error-authgroupfile/</id>
    <content type="html">&lt;p&gt;I noticed with the Virtualmin export feature that the Apache htpasswd sometimes doesn’t carry through when you import the package, you’ll end up with an error similar to this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Tue Jan 19 10:54:22.551737 2016] [core:alert] [pid 28447] [client 1.2.3.4:55007] /home/website/public_html/.htaccess: Invalid command &#39;AuthGroupFile&#39;, perhaps misspelled or defined by a module not included in the server configuration
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To fix this error, you’ll need to enable the &lt;code&gt;authz_groupfile&lt;/code&gt; module, for example on Ubuntu, you can use this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;a2enmod authz_groupfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restart Apache and it’ll start working as usual again.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Find Your Most Used Bash Commands</title>
    
    <link href="https://dor.ky/find-your-most-used-bash-commands/" rel="alternate" type="text/html"/>
    
    <updated>2016-01-17T10:36:24-00:00</updated>
    <id>https://dor.ky/find-your-most-used-bash-commands/</id>
    <content type="html">&lt;p&gt;If you want to see what your most used commands are within Terminal (will work on Linux too). You can run this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;history | awk &#39;{print $2}&#39; | sort | uniq -c | sort -rn | head
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Fix: Titanium &amp;#038; GenyMotion Player Not Found</title>
    
    <link href="https://dor.ky/fix-titanium-genymotion-player-not-found/" rel="alternate" type="text/html"/>
    
    <updated>2016-01-06T07:33:35-00:00</updated>
    <id>https://dor.ky/fix-titanium-genymotion-player-not-found/</id>
    <content type="html">&lt;p&gt;In the recent update of GenyMotion (Android Emulator) there’s a change which breaks its compatibility with Titanium Studio. You’ll need to open Terminal and create a symlink to fix it, start by opening Terminal and running:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /Applications/Genymotion.app/Contents/MacOS/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ln -s player.app/Contents/MacOS/player
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Shut Titanium Studio and GenyMotion both down and then restart Titanium Studio and it should work as usual after that point.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Real IP for Nginx / Laravel Forge when using Cloudflare</title>
    
    <link href="https://dor.ky/real-ip-for-nginx-laravel-forge-when-using-cloudflare/" rel="alternate" type="text/html"/>
    
    <updated>2016-01-04T12:11:43-00:00</updated>
    <id>https://dor.ky/real-ip-for-nginx-laravel-forge-when-using-cloudflare/</id>
    <content type="html">&lt;p&gt;If you use Cloudflare, you’ll need to configure Nginx to provide the real IP addresses, you can do this by installing&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt-get install nginx-extras
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then edit &lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt; and within the &lt;code&gt;http&lt;/code&gt; block add:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#CloudFlare
set_real_ip_from 199.27.128.0/21;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20; 
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
real_ip_header CF-Connecting-IP;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save the file, restart Nginx and then you’ll see the real user IP address within your app. You can read more about this on &lt;a href=&quot;https://support.cloudflare.com/hc/en-us/articles/200170706-How-do-I-restore-original-visitor-IP-with-Nginx-&quot;&gt;Cloudflare’s website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Remember to keep an eye on the Cloudflare IP list for changes.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Email Settings</title>
    
    <link href="https://dor.ky/email-settings/" rel="alternate" type="text/html"/>
    
    <updated>2016-01-01T10:50:05-00:00</updated>
    <id>https://dor.ky/email-settings/</id>
    <content type="html">&lt;p&gt;Each email box can store a max of 3GB if you’re using IMAP – but if you add the IMAP account to your phone and computer, they’ll stay in sync (ie, read messages, new mail etc). If you’re using POP3, it downloads the messages permanently to your computer and nowhere else (first to fetch gets the message).&lt;/p&gt;
&lt;p&gt;Username:&lt;/p&gt;
&lt;p&gt;Email address for the email box you’ve been given&lt;/p&gt;
&lt;p&gt;Password:&lt;/p&gt;
&lt;p&gt;Password for the email account you’ve been given&lt;/p&gt;
&lt;p&gt;Incoming/outgoing servers name:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://mail.privateemail.com/&quot;&gt;mail.privateemail.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Incoming server type:&lt;/p&gt;
&lt;p&gt;IMAP or POP3&lt;/p&gt;
&lt;p&gt;Incoming server (IMAP):&lt;/p&gt;
&lt;p&gt;993 port for SSL, 143 for TLS/STARTTLS&lt;/p&gt;
&lt;p&gt;Incoming server (POP3):&lt;/p&gt;
&lt;p&gt;995 port for SSL, 110 for TLS/STARTTLS&lt;/p&gt;
&lt;p&gt;Outgoing server (SMTP):&lt;/p&gt;
&lt;p&gt;465 port for SSL, 25 or 26 for TLS/STARTTLS&lt;/p&gt;
&lt;p&gt;Outgoing server authentication should be switched on, SPA (secure password authentication) must be disabled.&lt;/p&gt;
&lt;p&gt;You can also access webmail securely at &lt;a href=&quot;https://privateemail.com/&quot;&gt;https://privateemail.com&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Git Commit with A Random whatthecommit.com Message</title>
    
    <link href="https://dor.ky/git-commit-with-a-random-whatthecommit-com-message/" rel="alternate" type="text/html"/>
    
    <updated>2015-12-30T11:37:45-00:00</updated>
    <id>https://dor.ky/git-commit-with-a-random-whatthecommit-com-message/</id>
    <content type="html">&lt;p&gt;Probably shouldn’t advise people to do this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git commit -m `curl --silent http://whatthecommit.com/index.txt`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’ll commit your current state with a random message from the fantastic &lt;a href=&quot;http://whatthecommit.com/&quot;&gt;whatthecommit.com&lt;/a&gt; website.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Docker + rtorrent = Docktorrent</title>
    
    <link href="https://dor.ky/docker-rtorrent-docktorrent/" rel="alternate" type="text/html"/>
    
    <updated>2015-12-29T12:08:16-00:00</updated>
    <id>https://dor.ky/docker-rtorrent-docktorrent/</id>
    <content type="html">&lt;p&gt;I download a lot of linux images, by far the quickest way is via torrent. Recently discovered a nice implementation of rtorrent in a Docker image, via &lt;a href=&quot;https://github.com/kfei/docktorrent&quot;&gt;docktorrent&lt;/a&gt;, simple enough to run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -itd 
    --restart=always 
    --dns 8.8.8.8 
    -p 31405:80 
    -p 45566:45566 
    -p 9527:9527/udp 
    -v /path/to/mount/rtorrent:/rtorrent 
    -e UPLOAD_RATE=1024 
    kfei/docktorrent
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;31405&lt;/code&gt; is the public facing port for the web interface, make sure that you forward both &lt;code&gt;9527&lt;/code&gt; and &lt;code&gt;45566&lt;/code&gt; as it’ll need those to run.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Prevent OSX From Opening Photos or Image Capture Automatically</title>
    
    <link href="https://dor.ky/prevent-osx-from-opening-photos-or-image-capture-automatically/" rel="alternate" type="text/html"/>
    
    <updated>2015-12-24T11:17:50-00:00</updated>
    <id>https://dor.ky/prevent-osx-from-opening-photos-or-image-capture-automatically/</id>
    <content type="html">&lt;p&gt;Came across this OSX tip recently which will prevent Photos or Image Capture:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;defaults -currentHost write com.apple.ImageCapture disableHotPlug -bool YES
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Handling HTML Checkboxes with a default value</title>
    
    <link href="https://dor.ky/handling-checkboxes-in-php/" rel="alternate" type="text/html"/>
    
    <updated>2015-12-14T08:35:35-00:00</updated>
    <id>https://dor.ky/handling-checkboxes-in-php/</id>
    <content type="html">&lt;p&gt;I’ve used this tip myself previously, it’s useful if you want to set a default for a checkbox, such as false:&lt;/p&gt;
&lt;p&gt;Add an input of type “hidden”, and set the value to false before you declare the one with your true value, so for example, you could do this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;agree_to_terms&amp;quot; value=&amp;quot;false&amp;quot;&amp;gt;
&amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;agree_to_terms&amp;quot; value=&amp;quot;true&amp;quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There was &lt;a href=&quot;http://nielson.io/2014/02/handling-checkbox-input-in-laravel/&quot;&gt;this blog post&lt;/a&gt; that reminded me of this.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Recursive FTP Get with wget</title>
    
    <link href="https://dor.ky/recursive-ftp-get-with-wget/" rel="alternate" type="text/html"/>
    
    <updated>2015-12-14T07:33:31-00:00</updated>
    <id>https://dor.ky/recursive-ftp-get-with-wget/</id>
    <content type="html">&lt;p&gt;Pretty useful for downloading everything in an FTP account:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; wget -m --tries=0 --continue --server-response --timeout=0 --retry-connrefused ftp://username:password@server.tld
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Type Hinting in PHP7</title>
    
    <link href="https://dor.ky/type-hinting-in-php7/" rel="alternate" type="text/html"/>
    
    <updated>2015-12-08T07:58:27-00:00</updated>
    <id>https://dor.ky/type-hinting-in-php7/</id>
    <content type="html">&lt;p&gt;I’m happy that PHP7 has finally been released, I’ve been wanting to correctly return type hint for such a long time. You can now do this comfortably:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
declare(strict_types=1);

function getAge(int $age) : int {
    return $age;
}

echo var_dump(getAge(43));
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But more usefully, you can type hint interfaces to guarantee the classes you get returned (which is actually far, far more useful and beneficial).&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Paypal View IPN Log</title>
    
    <link href="https://dor.ky/paypal-view-ipn-log/" rel="alternate" type="text/html"/>
    
    <updated>2015-11-25T08:32:27-00:00</updated>
    <id>https://dor.ky/paypal-view-ipn-log/</id>
    <content type="html">&lt;p&gt;If you’re a Paypal user and use their IPN functionality, the link to get to the history page is hard to find. You can find it at:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.paypal.com/uk/cgi-bin/webscr?cmd=_display-ipns-history&quot;&gt;https://www.paypal.com/uk/cgi-bin/webscr?cmd=_display-ipns-history&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Google Search Quality Ratings</title>
    
    <link href="https://dor.ky/google-search-quality-ratings/" rel="alternate" type="text/html"/>
    
    <updated>2015-11-21T16:30:40-00:00</updated>
    <id>https://dor.ky/google-search-quality-ratings/</id>
    <content type="html">&lt;p&gt;Interesting new document provided by Google which details their &lt;a href=&quot;http://googlewebmastercentral.blogspot.co.uk/2015/11/updating-our-search-quality-rating.html&quot;&gt;search quality ratings&lt;/a&gt;. It’s nice to see them actually release something like this officially.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Tip: Add a prefix/suffix to each line of a file</title>
    
    <link href="https://dor.ky/tip-add-a-prefix-suffix-to-each-line-of-a-file/" rel="alternate" type="text/html"/>
    
    <updated>2015-10-29T20:28:24-00:00</updated>
    <id>https://dor.ky/tip-add-a-prefix-suffix-to-each-line-of-a-file/</id>
    <content type="html">&lt;p&gt;Pretty neat tip, I needed to add a prefix of ‘ufw deny from’ to a list of IP addresses in a file, you can do it easily with awk, using this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;awk &#39;$0=&amp;quot;ufw deny from &amp;quot;$0&#39; original.list &amp;gt; updated.list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And your updated.list file will now have each line prefixed. You can move the string around to get a suffix too.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Tip: Find String in PHP Files</title>
    
    <link href="https://dor.ky/tip-find-string-in-php-files/" rel="alternate" type="text/html"/>
    
    <updated>2015-10-23T13:24:49-00:00</updated>
    <id>https://dor.ky/tip-find-string-in-php-files/</id>
    <content type="html">&lt;p&gt;Helpful for finding strings in PHP files:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;find . -type f -name &#39;*.php&#39; -print0 | xargs -0 grep &#39;shell_exec&#39;
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Replace a RAID Hard Disk in OSX Based Servers</title>
    
    <link href="https://dor.ky/replace-a-raid-hard-disk-in-osx-based-servers/" rel="alternate" type="text/html"/>
    
    <updated>2015-10-21T18:55:32-00:00</updated>
    <id>https://dor.ky/replace-a-raid-hard-disk-in-osx-based-servers/</id>
    <content type="html">&lt;p&gt;I recently had to replace a hard disk in our OSX server at work. It had been a while since I had done this so I noted down the steps here to run through and change it. Work out which disk in your machine is faulty and replace it with a new drive.&lt;/p&gt;
&lt;p&gt;To get started, open up terminal and run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sh-3.2# diskutil list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will give you a list of all the disks in your machine:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/dev/disk0
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                  Apple_HFS Macintosh HD            999.9 GB   disk0s2
/dev/disk1
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk1
   1:                        EFI EFI                     209.7 MB   disk1s1
   2:                  Apple_HFS Server HD               999.3 GB   disk1s2
   3:                 Apple_Boot Recovery HD             650.0 MB   disk1s3
/dev/disk2
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *2.0 TB     disk2
   1:                        EFI EFI                     209.7 MB   disk2s1
   2:                  Apple_HFS Untitled 1              2.0 TB     disk2s2
/dev/disk3
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *2.0 TB     disk3
   1:                        EFI EFI                     209.7 MB   disk3s1
   2:                 Apple_RAID                         2.0 TB     disk3s2
   3:                 Apple_Boot Boot OS X               134.2 MB   disk3s3
/dev/disk4
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *2.0 TB     disk4
   1:                        EFI EFI                     209.7 MB   disk4s1
   2:                  Apple_HFS TimeMachine             2.0 TB     disk4s2
/dev/disk5
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:                  Apple_HFS Work                   *2.0 TB     disk5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new disk in this machine is &lt;code&gt;/dev/disk2&lt;/code&gt;. We now need to work out the Unique ID for our RAID array. So we’ll run the following command so that we can get our Unique ID:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sh-3.2# diskutil appleraid list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will provide the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;AppleRAID sets (1 found)
===============================================================================
Name:                 2TB Mirror
Unique ID:            E07AE421-43C5-4778-B1E3-DC3365F3266B
Type:                 Mirror
Status:               Degraded
Size:                 2.0 TB (2000054943744 Bytes)
Rebuild:              manual
Device Node:          disk5
-------------------------------------------------------------------------------
#  DevNode   UUID                                  Status     Size
-------------------------------------------------------------------------------
-  -none-    82D0A9C3-5ACB-4B3C-A4FC-FD473709E186  Missing/Damaged
1  disk3s2   81D8BD2A-894F-4720-8924-D4654001CF69  Online     2000054943744
===============================================================================
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we’ll add this disk to the existing array, the bad disk is listed in the array above as missing, because we’ve replaced it with a new disk.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sh-3.2# diskutil appleraid add member disk2 E07AE421-43C5-4778-B1E3-DC3365F3266B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will now perform an operation to add this disk to the RAID array:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Started RAID operation on disk5 Work
Unmounting disk
Repartitioning disk2 so it can be in a RAID set
Unmounting disk
Creating the partition map
Adding disk2s2 to the RAID Set
Finished RAID operation on disk5 Work 2012+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you’re now done for the addition of the drive. You now need to remove the old slice from the array by using this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sh-3.2# diskutil appleraid remove 82D0A9C3-5ACB-4B3C-A4FC-FD473709E186 E07AE421-43C5-4778-B1E3-DC3365F3266B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can now check that your RAID looks good by running:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sh-3.2# diskutil appleraid list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The RAID status should now be showing as &lt;code&gt;online&lt;/code&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Run PHP Script as Daemon Using Supervisord</title>
    
    <link href="https://dor.ky/run-php-script-as-daemon-using-supervisord/" rel="alternate" type="text/html"/>
    
    <updated>2015-10-18T11:34:49-00:00</updated>
    <id>https://dor.ky/run-php-script-as-daemon-using-supervisord/</id>
    <content type="html">&lt;p&gt;This short post is just a reminder for myself when writing supervisord configuration files, it’s extremely useful for running daemon workers (such as Laravel’s queue workers). You’ll need the &lt;code&gt;supervisor&lt;/code&gt; Ubuntu package installed.&lt;/p&gt;
&lt;p&gt;Create a file at &lt;code&gt;/etc/supervisor/conf.d/bob-program.conf&lt;/code&gt; and enter the file contents:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[program:bob-worker]
command=php /home/bob/worker.php
autostart=true
autorestart=true
user=bob
redirect_stderr=true
stdout_logfile=/home/bob/logs/worker.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then restart supervisor with &lt;code&gt;service supervisor restart&lt;/code&gt; and your program should launch.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Running Ubuntu Landscape-Server in Docker on Ubuntu 14.04</title>
    
    <link href="https://dor.ky/running-ubuntu-landscape-server-in-docker-on-ubuntu-14-04/" rel="alternate" type="text/html"/>
    
    <updated>2015-10-08T20:12:42-00:00</updated>
    <id>https://dor.ky/running-ubuntu-landscape-server-in-docker-on-ubuntu-14-04/</id>
    <content type="html">&lt;p&gt;If you use a few Ubunutu servers then you may have come across their management product called Landscape. It’s a pretty complex solution to set up, however with advances in Docker and useful work from the UK Home Office, there is now a Docker image you can use to run it, take a look at &lt;a href=&quot;https://github.com/UKHomeOffice/docker-landscaper-server&quot;&gt;this Github repo&lt;/a&gt; for more information.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Adding Additional IPs to Linode Servers</title>
    
    <link href="https://dor.ky/adding-additional-ips-to-linode-servers/" rel="alternate" type="text/html"/>
    
    <updated>2015-10-08T19:55:30-00:00</updated>
    <id>https://dor.ky/adding-additional-ips-to-linode-servers/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;Update: I no longer use Linode, but I had this draft laying here, so decided to publish anyhow.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you have an additional IP address on your Linode Ubuntu box, you’ll need to add it to your &lt;code&gt;/etc/network/interfaces&lt;/code&gt; file, so open that up using &lt;code&gt;nano&lt;/code&gt; or a similar tool, you’ll need to add &lt;code&gt;eth0:1&lt;/code&gt; to the auto line, then an &lt;code&gt;iface&lt;/code&gt; block, so that it looks similar to this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# The loopback network interface
auto lo eth0 eth0:1 eth0:2
iface lo inet loopback

# The primary network interface
iface eth0 inet static
  address 85.159.209.124
  netmask 255.255.255.0
  gateway 85.159.209.1

iface eth0:1 inet static
  address 109.237.26.62
  netmask 255.255.255.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save that file, restart networking and then try pinging your new IP address.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Running Ghost in Docker on Ubuntu 14.04</title>
    
    <link href="https://dor.ky/running-ghost-in-docker-on-ubuntu-14-04/" rel="alternate" type="text/html"/>
    
    <updated>2015-10-08T19:55:07-00:00</updated>
    <id>https://dor.ky/running-ghost-in-docker-on-ubuntu-14-04/</id>
    <content type="html">&lt;p&gt;If you’re interested in running Ghost for your blog inside Docker. It’s pretty simple to get it up and running.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --name=ghost --restart=always -d -p 123.123.123.123:80:2368 -v /docker/data-volumes/ghost:/var/lib/ghost ghost
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I found it better to use a data volume with a mount point of /var/lib/ghost to get it running. The following links were useful in getting up and running:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://allaboutghost.com/deploying-ghost-with-docker/&quot;&gt;https://allaboutghost.com/deploying-ghost-with-docker/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/docker-library/ghost/issues/7&quot;&gt;https://github.com/docker-library/ghost/issues/7&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Running PHPUnit in Isolated Environments with Ubuntu, Docker, Gitlab &amp;#038; Gitlab CI</title>
    
    <link href="https://dor.ky/running-phpunit-in-isolated-environments-with-ubuntu-docker-gitlab-gitlab-ci/" rel="alternate" type="text/html"/>
    
    <updated>2015-10-03T17:27:17-00:00</updated>
    <id>https://dor.ky/running-phpunit-in-isolated-environments-with-ubuntu-docker-gitlab-gitlab-ci/</id>
    <content type="html">&lt;p&gt;I’m currently working on a new project that houses a framework for multi-tenant applications based on Laravel. The source code is stored in a hosted Gitlab instance via &lt;a href=&quot;http://githost.io/&quot;&gt;Githost.io&lt;/a&gt; – which is run by &lt;a href=&quot;http://gitlab.com/&quot;&gt;Gitlab&lt;/a&gt; themselves. There’s a set of unit tests that I wanted to run via continuous integration to run the tests with each commit and fast.&lt;/p&gt;
&lt;p&gt;Throughout this post, the &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt; daemon is running at &lt;code&gt;tcp://192.168.1.254:4243/&lt;/code&gt; instead of via a socket. This is because I use the API for other things over HTTP.&lt;/p&gt;
&lt;p&gt;The local development environment is handled by Vagrant, using a custom box based upon Ubuntu that includes Composer, MariaDB and a few other components. This works very well, one simple Vagrantfile can be dropped in to new projects and immediately get running with a LAMP style stack:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Vagrant.configure(&amp;quot;2&amp;quot;) do |config|
    config.vm.provider :virtualbox do |v|
        v.name = &amp;quot;mult&amp;quot;
        v.customize [&amp;quot;modifyvm&amp;quot;, :id, &amp;quot;--memory&amp;quot;, 2048]
        config.vm.box = &amp;quot;ssx/lamp&amp;quot;
        config.vm.network :private_network, ip: &amp;quot;192.168.13.37&amp;quot;
        config.ssh.forward_agent = true
    end

    config.vm.synced_folder &amp;quot;./&amp;quot;, &amp;quot;/vagrant&amp;quot;, type: &amp;quot;nfs&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This box works quite well, but to Vagrant up and run tests using this with every commit would be quite slow. Enter &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt;. I converted the image that was used in the Vagrant environment to a Docker one and now tests can be ran within seconds instead of minutes.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://about.gitlab.com/gitlab-ci/&quot;&gt;Gitlab CI&lt;/a&gt; has a &lt;a href=&quot;http://doc.gitlab.com/ci/docker/using_docker_images.html&quot;&gt;Docker mode of operation&lt;/a&gt;. I couldn’t quite seem to get that up and running well. You can find the instructions for &lt;a href=&quot;https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/linux-repository.md&quot;&gt;installing a Gitlab CI runner on this page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I went via the shell route and writing the Docker commands manually to boot up in container and then run our script and tests, in the repo I have &lt;code&gt;build.sh&lt;/code&gt; which must be set to +x to execute:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/env bash

# Restart the services within the container
service mysql restart
service nginx restart
service php5-fpm restart

# Move into the directory
cd /vagrant

# Run our migrations
php artisan migrate
php artisan db:seed

# Execute our test suite
vendor/bin/phpunit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file needs to be created to run the build and then tests:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stages:
  - test

job1:
    stage: test
    script: 
     - composer install
     - cp .env.example .env
     - php artisan key:generate
     - docker run -d -t -v `pwd`:/vagrant hellossx/lamp:1.0.4 &amp;gt; container.pid
     - docker exec `cat container.pid` /vagrant/build.sh
    tags:
     - docker
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This does mean that if tests fail, the container will never get cleaned up. You can add a cronjob to clean up these orphaned containers, with something like this &lt;code&gt;docker-clear-old.sh&lt;/code&gt; script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Set our docker host
export DOCKER_HOST=&amp;quot;tcp://192.168.1.254:4243/&amp;quot;

# Clean up old images that failed tests
for i in $(docker ps -a | grep &amp;quot;hour ago&amp;quot; | cut -f1 -d&amp;quot; &amp;quot;); do docker stop $i &amp;amp;&amp;amp; docker rm $i; done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will remove the containers after an hour and leave the previous ones around for a short while incase you want to attach and investigate anything.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Enabling Docker Remote API on Ubuntu</title>
    
    <link href="https://dor.ky/enabling-docker-remote-api-on-ubuntu/" rel="alternate" type="text/html"/>
    
    <updated>2015-10-02T22:14:32-00:00</updated>
    <id>https://dor.ky/enabling-docker-remote-api-on-ubuntu/</id>
    <content type="html">&lt;p&gt;If you need to enable the remote API on an Ubuntu 14.04 based system for Docker, you need to do the following, edit the file located at:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/etc/default/docker
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and just under the line that contains something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Use DOCKER_OPTS to modify the daemon startup options.
# DOCKER_OPTS=&amp;quot;--dns 8.8.8.8 --dns 8.8.4.4&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;add in your own entry. For example, if you want to listen on 10.0.0.2, port 4243:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DOCKER_OPTS=&amp;quot;-H tcp://10.0.0.2:4243&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then restart docker using:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;service docker restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Confirm it’s now running by pointing your browser at &lt;a href=&quot;http://10.0.0.2:4243/images/search?term=hello&quot;&gt;http://10.0.0.2:4243/images/search?term=hello&lt;/a&gt; which should return some JSON with image names. You’ll need to set the environment variable for the docker CLI command as well, this should work for you:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export DOCKER_HOST=tcp://10.0.0.2:4243
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then restart your shell and it should work as usual.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tip&lt;/em&gt;: If you’re using New Relic to monitor Docker containers, you’ll need this turned on for it to work properly.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Virtualbox does not start on Mac OSX</title>
    
    <link href="https://dor.ky/virtualbox-does-not-start-on-mac-os-x/" rel="alternate" type="text/html"/>
    
    <updated>2015-09-02T11:27:47-00:00</updated>
    <id>https://dor.ky/virtualbox-does-not-start-on-mac-os-x/</id>
    <content type="html">&lt;p&gt;If you’ve recently upgraded your Mac to OSX El Capitan and you have an issue where Virtualbox has decided to no longer work, try this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for bin in VirtualBox VirtualBoxVM VBoxNetAdpCtl VBoxNetDHCP VBoxNetNAT VBoxHeadless; do
    sudo chmod u+s &amp;quot;/Applications/VirtualBox.app/Contents/MacOS/${bin}&amp;quot;
done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Found via &lt;a href=&quot;http://superuser.com/questions/620936/virtualbox-does-not-start-on-mac-os-x&quot;&gt;this link&lt;/a&gt; on StackOverflow.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Delete a Remote Git Tag</title>
    
    <link href="https://dor.ky/delete-a-remote-git-tag/" rel="alternate" type="text/html"/>
    
    <updated>2015-08-29T12:12:06-00:00</updated>
    <id>https://dor.ky/delete-a-remote-git-tag/</id>
    <content type="html">&lt;p&gt;Just a note more to myself as I always forget the syntax of this one. To delete a tag both local and remote:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git tag -d tag_name &amp;amp;&amp;amp; git push origin :refs/tags/tag_name
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Vagrant + VirtualBox + Update Tools</title>
    
    <link href="https://dor.ky/vagrant-virtualbox-update-tools/" rel="alternate" type="text/html"/>
    
    <updated>2015-07-29T20:14:53-00:00</updated>
    <id>https://dor.ky/vagrant-virtualbox-update-tools/</id>
    <content type="html">&lt;p&gt;If you’re a Vagrant user that uses Virtualbox to host your machines, sometimes the Virtualbox tools in the guest VM will get out of date. There’s a great Vagrant plugin that will run an update for you. Run the following command to install it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vagrant plugin install vagrant-vbguest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a far more detailed description over on this &lt;a href=&quot;http://kvz.io/blog/2013/01/16/vagrant-tip-keep-virtualbox-guest-additions-in-sync/&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Travel Tip: Send Google Maps Location to Mobile Device</title>
    
    <link href="https://dor.ky/travel-tip-send-google-maps-location-to-mobile-device/" rel="alternate" type="text/html"/>
    
    <updated>2015-07-21T16:10:57-00:00</updated>
    <id>https://dor.ky/travel-tip-send-google-maps-location-to-mobile-device/</id>
    <content type="html">&lt;p&gt;If you’re signed in to your Google account, you can click on a pin then click ‘Send to Mobile Device’. This will forward the location over to your device.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/google_maps1.png&quot; alt=&quot;Google Maps&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/google_maps2-1.png&quot; alt=&quot;Google Maps&quot;&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Adding Backups to Your Laravel Project</title>
    
    <link href="https://dor.ky/adding-backups-to-your-laravel-project/" rel="alternate" type="text/html"/>
    
    <updated>2015-07-07T19:24:21-00:00</updated>
    <id>https://dor.ky/adding-backups-to-your-laravel-project/</id>
    <content type="html">&lt;p&gt;If you have a Laravel project and need a simple backup solution, I’d recommend &lt;a href=&quot;https://github.com/ShawnMcCool/database-backup&quot;&gt;Shawn McCool’s database-backup&lt;/a&gt;. Follow the instructions to get that configured to your liking and you can then cron a task like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;php artisan db:backup --destinationPath=`hostname`-`date +%Y-%m-%d`.sql --destination=dropbox --database=mysql --compression=gzip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To automatically stick a daily backup to Dropbox or any other filesystem provider supported by Flysystem.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Generate Private Keys &amp;#038; CSR for an SSL Cert</title>
    
    <link href="https://dor.ky/generate-private-keys-csr-for-an-ssl-cert/" rel="alternate" type="text/html"/>
    
    <updated>2015-07-06T23:05:04-00:00</updated>
    <id>https://dor.ky/generate-private-keys-csr-for-an-ssl-cert/</id>
    <content type="html">&lt;p&gt;Something I always tend to have to Google for the right syntax is generating a CSR for an SSL along with a set of keys for it, this post by Google themselves has a good reference:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/fundamentals/discovery-and-distribution/security-with-https/generating-keys-and-csr?hl=en&quot;&gt;Generating keys and CSR – Web Fundamentals&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Woes of Cloudflare SSL</title>
    
    <link href="https://dor.ky/woes-of-cloudflare-ssl/" rel="alternate" type="text/html"/>
    
    <updated>2015-07-03T18:20:00-00:00</updated>
    <id>https://dor.ky/woes-of-cloudflare-ssl/</id>
    <content type="html">&lt;p&gt;I recently switched &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt; over to serve as SSL via Cloudflare and for the most part, this has been a good transition for most people. There have been the odd reports of people having issues though. I looked into this a bit more and it comes down to the types of certs stored in some phones and browsers – I don’t think they’re out of date per-se, but I don’t think they support a certain cipher, which is what makes them fail.&lt;/p&gt;
&lt;p&gt;There’s some good information over on &lt;a href=&quot;http://forums.opera.com/discussion/1850720/opera-12-17-no-longer-works-with-https-for-me/p1&quot;&gt;this blog post&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Tweekly.fm Changes</title>
    
    <link href="https://dor.ky/tweekly-fm-changes/" rel="alternate" type="text/html"/>
    
    <updated>2015-06-23T19:21:12-00:00</updated>
    <id>https://dor.ky/tweekly-fm-changes/</id>
    <content type="html">&lt;p&gt;If you’re reading this post, you are most likely a user of &lt;a href=&quot;http://tweekly.fm/&quot;&gt;Tweekly.fm&lt;/a&gt;. I’d like to take a little time to write about the changes that have recently happened on the site.&lt;/p&gt;
&lt;p&gt;I’d like to note that I have come across some of the most fantastic people in the world through this humble small service and want to see it continue for a long period of time – but to do that things needed to change.&lt;/p&gt;
&lt;h2 id=&quot;what-is-tweekly.fm%3F&quot;&gt;What is &lt;a href=&quot;http://tweekly.fm/&quot;&gt;Tweekly.fm&lt;/a&gt;?&lt;/h2&gt;
&lt;p&gt;The main functionality of the site takes data that you have provided via &lt;a href=&quot;http://last.fm/&quot;&gt;Last.fm&lt;/a&gt; and posts it, once per week to social networks.&lt;/p&gt;
&lt;p&gt;This in itself sounds like a very simple system that has multiple parts within it. Every day, thousands upon thousands of updates are posted to Facebook and Twitter – which take a lot of time and consume a lot of resources to do so. Previously, Google Ads were ran across the site which generated a low amount of income which didn’t cover the cost of keeping the service up and running. The were unattractive and not a good fit for the service.&lt;/p&gt;
&lt;h2 id=&quot;crowdfunding&quot;&gt;Crowdfunding&lt;/h2&gt;
&lt;p&gt;As most of the regular users who use the service know, I attempted to run a crowd funding programme earlier in the year, which did generate enough money to contribute to the hosting costs and some of the development time in updating the site and services that you use.&lt;/p&gt;
&lt;p&gt;While the new site has been built, I took time to decide how the new service should run, what the foundations of the service should be and how this can be attained – without financial impact on me personally. I didn’t want to use Google Ads on the new site and as you can see, they’re not present and won’t be.&lt;/p&gt;
&lt;h2 id=&quot;support&quot;&gt;Support&lt;/h2&gt;
&lt;p&gt;The biggest cost besides hosting the service is the amount of time answering support tickets and emails. This gets done in my own free time and outside of my 9-5 job. No service is without bugs or hiccups – but a lot of general questions take time to answer and if you’ve ever emailed I’d like to think you got a response quite quickly.&lt;/p&gt;
&lt;h2 id=&quot;what%E2%80%99s-the-cost%3F&quot;&gt;What’s the cost?&lt;/h2&gt;
&lt;p&gt;The service runs on Linode using a mixture of servers, which for the most part consisted of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 x 2GB Linode ($20×2 + $10×2) – Web servers&lt;/li&gt;
&lt;li&gt;2 x 2GB Linode ($20×2 + $10×2) – Queue runners, queue daemons&lt;/li&gt;
&lt;li&gt;1 x NodeBalancer (1x$20) – Load Balancer&lt;/li&gt;
&lt;li&gt;2 x 4GB ($40×2 + 2x$10 Backups) – Database (Master and Slave)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you see, this comes in at $240/mo which for a service that doesn’t generate a lot of money, is a costly expense that I’ve been happy to cover for a long time. I should also note that the project has very kindly received hosting from &lt;a href=&quot;http://last.fm/&quot;&gt;Last.fm&lt;/a&gt; directly in the past and in the early years this was absolutely key to the project. For the new site, the requirements are about half of those servers.&lt;/p&gt;
&lt;h2 id=&quot;external-integrations&quot;&gt;External Integrations&lt;/h2&gt;
&lt;p&gt;The last time consumer is keeping up with the external services that are used. Each time Twitter, Facebook and co update their APIs, I needed to change a lot of in-house code to match. During the development of the new system, everything has been moved over to Laravel 5.1 and a lot of standard libraries have been used in the codebase to improve and minimise the amount of time needed for upkeep.&lt;/p&gt;
&lt;h2 id=&quot;so%2C-what-happens-now%3F&quot;&gt;So, what happens now?&lt;/h2&gt;
&lt;p&gt;The biggest issue for the service was dealing with the amount of traffic that came back to the site once updates are posted, so the new system has no public facing profile pages at the moment. The only place that people can see your updates are on your social media profiles.&lt;/p&gt;
&lt;p&gt;Secondly, the largest time consuming task was auto-publishing all the thousands of updates per day – this has now been changed to a premium user feature. You can still sign up for free and continue to post your updates manually – without a charge. This will always remain the case, but for the future auto-posting updates will be limited to those with a subscription.&lt;/p&gt;
&lt;p&gt;The changes to the support ticket system are also now in favour of subscribed users. Any support emails from subscribers will be answered first and the rest at some point later in the week.&lt;/p&gt;
&lt;p&gt;I know this is quite a change to how the service previously ran and I also accept that some of you may not want to subscribe – I have absolutely no issues with that but I hope you can readdress your expectations in what you want from me.&lt;/p&gt;
&lt;p&gt;There has already been a number of folks sign up for premium accounts and for those I’m grateful that you place a value on the service provided.&lt;/p&gt;
&lt;p&gt;As always, if you have any questions, ideas or thoughts then please do use the comments below or if you would like to discuss in private, contact &lt;a href=&quot;mailto:support@tweekly.fm&quot;&gt;support@tweekly.fm&lt;/a&gt; and I’ll be happy to talk.&lt;/p&gt;
&lt;p&gt;Lastly, thank you to all half a million &lt;a href=&quot;http://tweekly.fm/&quot;&gt;Tweekly.fm&lt;/a&gt; users from around the world – it’s been one hell of a ride so far and I’m glad to have provided you with a service you enjoy.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Migrating Data From Runkeeper to Strava</title>
    
    <link href="https://dor.ky/migrating-data-from-runkeeper-to-strava/" rel="alternate" type="text/html"/>
    
    <updated>2015-05-31T13:52:33-00:00</updated>
    <id>https://dor.ky/migrating-data-from-runkeeper-to-strava/</id>
    <content type="html">&lt;p&gt;Just a quick note, if you have previous used the Runkeeper platform and want to migrate your data over to Strava, there is a fantastic online tool that will do it for you called &lt;a href=&quot;https://tapiriik.com/&quot;&gt;tapiriik.com&lt;/a&gt;. I’ve used it to bulk import all of my ride data over and it’s been flawless.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Automating Docker on a Gitlab CI Server</title>
    
    <link href="https://dor.ky/docker-on-a-ci-server/" rel="alternate" type="text/html"/>
    
    <updated>2015-05-12T19:44:10-00:00</updated>
    <id>https://dor.ky/docker-on-a-ci-server/</id>
    <content type="html">&lt;p&gt;I’ve currently been setting &lt;a href=&quot;http://www.docker.com/&quot;&gt;docker&lt;/a&gt; up to run containers for a Gitlab CI server. The basic premise is that the CI server will &lt;a href=&quot;https://www.vagrantup.com/&quot;&gt;vagrant&lt;/a&gt; up a box, run ansible and finally run phpunit.&lt;/p&gt;
&lt;p&gt;This has worked well, however getting the docker containers to destroy afterwards hasn’t been as clean cut.&lt;/p&gt;
&lt;p&gt;From using a few other sources, I’m using this script via cron which runs every five minutes to stop and remove any containers that have been running for more than an hour (this is working for our current commit frequency but will need addresses as more things are moved to this CI server).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@ci-runner:~# cat docker-clear-old.sh 
#!/bin/bash
for i in $(docker ps -a | grep &amp;quot;hour ago&amp;quot; | cut -f1 -d&amp;quot; &amp;quot;); do docker stop $i &amp;amp;&amp;amp; docker rm $i; done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is working quite well so far, I’d be interested in how you’re doing this if you’re a docker user too.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Git: Remove Non Project Files from Repository</title>
    
    <link href="https://dor.ky/git-remove-non-project-files-from-repository/" rel="alternate" type="text/html"/>
    
    <updated>2015-04-29T16:36:51-00:00</updated>
    <id>https://dor.ky/git-remove-non-project-files-from-repository/</id>
    <content type="html">&lt;p&gt;A quick tip that I always seem to forget, if you need to quickly remove any non project files form a repo, check this Stack Overflow answer out:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/5037480/removing-non-repository-files-with-git&quot;&gt;http://stackoverflow.com/questions/5037480/removing-non-repository-files-with-git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In short, I think I used this in the end:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clean -df
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which removed and deleted any files not in the git index.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Ubuntu Server Management with Landscape</title>
    
    <link href="https://dor.ky/ubuntu-server-management-with-landscape/" rel="alternate" type="text/html"/>
    
    <updated>2015-04-17T14:56:56-00:00</updated>
    <id>https://dor.ky/ubuntu-server-management-with-landscape/</id>
    <content type="html">&lt;p&gt;Both at work and personally, I run a lot of Ubuntu servers. It’s now the standard OS choice for any new servers too. To help with management of these servers, I’ve settled on a combination of New Relic’s server monitoring (and app monitoring for a certain few apps) and the self-hosted/dedicated version of Canonical’s &lt;a href=&quot;https://landscape.canonical.com/&quot;&gt;Landscape Dedicated Server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It’s pretty simple to get set up. You’ll need a server running Ubuntu to install it on. I chose a &lt;a href=&quot;https://www.digitalocean.com/?refcode=81506f208a74&quot;&gt;Digital Ocean $20 droplet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Create your droplet, run all current updates and check that that hostname is a FQDN. Next, login to the box and switch to root.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add-apt-repository ppa:landscape/15.01
apt-get update
apt-get install landscape-server-quickstart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this has finished, you will now have an SSL cert at &lt;code&gt;/etc/ssl/certs/landscape_server_ca.crt&lt;/code&gt; which you need to copy and make a note of.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@landscape-server:~# cat /etc/ssl/certs/landscape_server_ca.crt
-----BEGIN CERTIFICATE-----
MIICAzCCAWygAwIBAgIJANbXg3JbmTu9MA0GCSqGSIb3DQEBCwUAMCYxJDAiBgNV
...
[snipped]
...
3fJBHsY6i5i70Gq/5FUV7O7bP7/wnLKIljrO7gI/d5DNEQmXUkgY
-----END CERTIFICATE-----
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make a safe note of the contents of that file. Next, switch over to your client server, and run the following as &lt;code&gt;root&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@landscape-client:~# mkdir /etc/landscape
root@landscape-client:~# apt-get install landscape-client
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will install the landscape client. Next, create the file &lt;code&gt;/etc/landscape/server.pem&lt;/code&gt; and then paste the contents of the server SSL cert into this file.&lt;/p&gt;
&lt;p&gt;After this, you need to add the variable &lt;code&gt;ssl_public_key&lt;/code&gt; to your Landscape configuration file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo ssl_public_key = /etc/landscape/server.pem &amp;gt;&amp;gt; /etc/landscape/client.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final step is to run the configuration utility on the client machine:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@landscape-client:~# landscape-config --computer-title `hostname` --account-name standalone  --url https://landscape-server/message-system --ping-url http://landscape-server/ping
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll be asked a few questions about getting setup and what to allow, tags to use etc. Customise to suit and then register the machine when prompted. If you get a connection error then check you’ve pasted the certificate correctly and added the &lt;code&gt;ssl_public_key&lt;/code&gt; variable correctly too.&lt;/p&gt;
&lt;p&gt;A couple of links that were useful reference:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://askubuntu.com/questions/549809/how-do-i-install-landscape-for-personal-use&quot;&gt;http://askubuntu.com/questions/549809/how-do-i-install-landscape-for-personal-use&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://help.landscape.canonical.com/LDS/QuickstartDeployment14.10&quot;&gt;https://help.landscape.canonical.com/LDS/QuickstartDeployment14.10&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>PHPStorm: Set your shell to ZSH</title>
    
    <link href="https://dor.ky/phpstorm-set-your-shell-to-zsh/" rel="alternate" type="text/html"/>
    
    <updated>2015-03-26T20:39:46-00:00</updated>
    <id>https://dor.ky/phpstorm-set-your-shell-to-zsh/</id>
    <content type="html">&lt;p&gt;If you’re a PHPStorm user and also use oh-my-zsh, you can set your default shell to be ZSH in the settings. Head into the preferences, select &lt;code&gt;Terminal&lt;/code&gt;, then there is a box for &lt;code&gt;Shell Path&lt;/code&gt;, stick in your zsh path – usually &lt;code&gt;/bin/zsh&lt;/code&gt; on the mac, like so:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/phpstorm_zsh.png&quot; alt=&quot;PHPStorm Configuration Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now when you use the Terminal panel, it’ll be zsh instead of bash:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/phpstorm_zsh_terminal.png&quot; alt=&quot;ZSH Terminal within PHPStorm&quot;&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>GPS for Unlocking Train Doors</title>
    
    <link href="https://dor.ky/gps-for-unlocking-train-doors/" rel="alternate" type="text/html"/>
    
    <updated>2015-03-16T18:10:33-00:00</updated>
    <id>https://dor.ky/gps-for-unlocking-train-doors/</id>
    <content type="html">&lt;p&gt;I came across this web page a few days ago which describe an issue with ThamesLink trains having their doors getting stuck due to GPS blackouts. You can read the full article over at &lt;a href=&quot;http://www.ciras.org.uk/report-library/train-operations/52131-issue-with-opening-class-377-doors-on-the-thameslink-route/&quot;&gt;ciras.org.uk&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Vagrantfile for Open Source Version of Odoo (formally OpenERP)</title>
    
    <link href="https://dor.ky/vagrantfile-for-open-source-version-of-odoo-formally-openerp/" rel="alternate" type="text/html"/>
    
    <updated>2015-03-08T17:37:10-00:00</updated>
    <id>https://dor.ky/vagrantfile-for-open-source-version-of-odoo-formally-openerp/</id>
    <content type="html">&lt;p&gt;A couple of colleagues and I have recently been looking at &lt;a href=&quot;https://www.odoo.com/&quot;&gt;Odoo&lt;/a&gt;, there is an open source version which you can self host. There didn’t seem to be any recent Vagrant based versions of this, so I’ve put one together which you can clone from:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/ssx/vagrant-odoo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vagrant up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’ll then get the latest install script, run it and get the environment set up. Theres more information in the &lt;a href=&quot;http://readme.md/&quot;&gt;readme.md&lt;/a&gt; file within the repo as well.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Find Installed Packages on Ubuntu (and dpkg) Systems</title>
    
    <link href="https://dor.ky/find-installed-packages-on-ubuntu-and-dpkg-systems/" rel="alternate" type="text/html"/>
    
    <updated>2015-03-06T22:55:02-00:00</updated>
    <id>https://dor.ky/find-installed-packages-on-ubuntu-and-dpkg-systems/</id>
    <content type="html">&lt;p&gt;To get a list of all the installed packages on an Ubuntu or dpkg based server, you can use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dpkg --get-selections | grep -v deinstall
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Using an External SMTP Server with Gitlab</title>
    
    <link href="https://dor.ky/using-an-external-smtp-server-with-gitlab/" rel="alternate" type="text/html"/>
    
    <updated>2015-01-10T18:57:02-00:00</updated>
    <id>https://dor.ky/using-an-external-smtp-server-with-gitlab/</id>
    <content type="html">&lt;p&gt;If you run a &lt;a href=&quot;https://about.gitlab.com/downloads/&quot;&gt;Gitlab server&lt;/a&gt; and you need to use a custom SMTP service, there is a good set of instructions over at Elijah Paul’s blog:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://elijahpaul.co.uk/using-an-smtp-server-with-gitlab/&quot;&gt;http://elijahpaul.co.uk/using-an-smtp-server-with-gitlab/&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Recursively Update File &amp;#038; Directory Timestamps</title>
    
    <link href="https://dor.ky/recursively-update-file-directory-timestamps/" rel="alternate" type="text/html"/>
    
    <updated>2014-12-29T20:15:01-00:00</updated>
    <id>https://dor.ky/recursively-update-file-directory-timestamps/</id>
    <content type="html">&lt;p&gt;If you need to update the modified timestamp of a set of files recursively, you can use the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;find . -exec touch {} ;
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Cronjob an RBL Check</title>
    
    <link href="https://dor.ky/cronjob-an-rbl-check/" rel="alternate" type="text/html"/>
    
    <updated>2014-12-28T12:39:10-00:00</updated>
    <id>https://dor.ky/cronjob-an-rbl-check/</id>
    <content type="html">&lt;p&gt;There’s a fantastic website that you can run &lt;code&gt;curl&lt;/code&gt; to fetch a list of the blacklist and simple mail checks to ensure any of your servers that send mail aren’t blacklisted.&lt;/p&gt;
&lt;p&gt;Create a new file at &lt;code&gt;/etc/cron.daily/rblchecker&lt;/code&gt; and place these contents in:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/sh
/usr/bin/curl checkrbl.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then make it executable &lt;code&gt;chmod +x /etc/cron.daily/rblchecker&lt;/code&gt; and it’ll run. You may need to adjust the path to &lt;code&gt;curl&lt;/code&gt;. When it runs, you’ll get the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;===================================
CheckRBL.com - Comments, suggestions and bug reports: feedback@checkrbl.com
IP CHECK FOR 85.159.213.127
===================================

RBL Checks
-----------------------------------
 - not listed in Backscatterer
 - not listed in Barracuda Central
 - not listed in McAfee
 - not listed in SenderScore
 - not listed in SpamCop
 - not listed in SpamHaus PBL
 - not listed in SpamHaus SBL
 - not listed in SpamHaus XBL
 - not listed in UCE-Protect

Reverse Record Check
-----------------------------------
Reverse Record present: aeson.ssx.io

SMTP port check
-----------------------------------
Connected to 85.159.213.127 on port 25, mail banner says: aeson.ssx.io.
Found &#39;A&#39; Record for aeson.ssx.io: 85.159.213.127
DNS &#39;A&#39; record for aeson.ssx.io matches the given IP 85.159.213.127

Results
-----------------------------------
GOOD: Reverse record matches SMTP banner, 3-way mailcheck PASS.
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Gitlab Droplet on Digital Ocean &amp;#8211; Add a robots.txt</title>
    
    <link href="https://dor.ky/gitlab-droplet-on-digital-ocean-add-a-robots-txt/" rel="alternate" type="text/html"/>
    
    <updated>2014-12-25T17:32:13-00:00</updated>
    <id>https://dor.ky/gitlab-droplet-on-digital-ocean-add-a-robots-txt/</id>
    <content type="html">&lt;p&gt;If you’re using Digital Ocean’s Gitlab droplet, it’ll give you a fully configured instance for you to start using straight away. The most often case for people using Gitlab is for private repositories, if that’s the case for you then it’s worth creating a file at:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/opt/gitlab/embedded/service/gitlab-rails/public/robots.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then putting a disallow rule in such as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User-Agent: *
Disallow: /
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although not a massive security feature it should stop your public facing stuff from showing up on search engines.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>State of Tweekly.fm &amp;#8211; December 2014</title>
    
    <link href="https://dor.ky/state-of-tweekly-fm/" rel="alternate" type="text/html"/>
    
    <updated>2014-12-13T18:01:38-00:00</updated>
    <id>https://dor.ky/state-of-tweekly-fm/</id>
    <content type="html">&lt;p&gt;It’s been quite a few months for the &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt; project. The original plan was to rewrite the user facing side of the service. Instead of just this, the entire platform was rewritten. The API’s that power the publishing of updates and collection of user data were rewritten from the ground up.&lt;/p&gt;
&lt;p&gt;The site and APIs have also been moved over the new servers and architecture and now are loadbalanced which allows around 10,000 connections a second – this will mean you should no longer get timeouts on Sundays and more updates can be sent.&lt;/p&gt;
&lt;p&gt;You will now have one &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt; account that you can add connections to. This includes support for Twitter, Facebook, Tumblr, WordPress, AppDotNet and more to come. Each one of these services can be independently configured.&lt;/p&gt;
&lt;p&gt;This has enabled me to begin work on developing iOS and Android apps that can interact with the &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt; service. This includes managing your account and posting new updates from your phone.&lt;/p&gt;
&lt;p&gt;There will be two versions of the &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt; app. The free version will allow premium users to manage their account and post updates across any of their linked accounts. There will also be a low cost ($0.99/£0.69) version which allows you to create updates on your phone – independent of the &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt; service.&lt;/p&gt;
&lt;p&gt;The people who donated earlier this year will receive a free upgrade to a premium account on the new platform and will be able to use the free version of the app. So that you’re aware, enough was raised earlier this year for about two weeks work on the service and platform.&lt;/p&gt;
&lt;p&gt;If you’re interested in beta testing the new iOS app then please complete this the form at &lt;a href=&quot;http://beta.tweekly.fm/&quot;&gt;http://beta.tweekly.fm&lt;/a&gt; and I’ll add you to the list.&lt;/p&gt;
&lt;p&gt;The launch date for both the new apps and website is going be 11th January 2015. This is due to a few things that still need ironing out with the frontend of the website – although the apps may land in the app store before this date.&lt;/p&gt;
&lt;p&gt;I’m still looking for sponsors/advertisers for the site as well, if you’re interested please contact &lt;a href=&quot;mailto:support@tweekly.fm&quot;&gt;support@tweekly.fm&lt;/a&gt;. I’ve also been considering using crowdfunding. If you would be willing to participate in crowdfunding more development of &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt;, then please post in the comments and I’ll see how much reaction there is and whether to set something up.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Fix Messages Stuck Offline on OSX</title>
    
    <link href="https://dor.ky/fix-messages-stuck-offline-on-osx/" rel="alternate" type="text/html"/>
    
    <updated>2014-11-29T20:14:01-00:00</updated>
    <id>https://dor.ky/fix-messages-stuck-offline-on-osx/</id>
    <content type="html">&lt;p&gt;Update: Nino (see comments) has written a blog post on how to automate this a little, read it at &lt;a href=&quot;http://rubyengineer.com/posts/2#title&quot;&gt;http://rubyengineer.com/posts/2&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you have an issue with Messages on OSX being stuck in ‘Offline’ mode that won’t connect, open up Terminal and type the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ps auxwww | grep imagent
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will give you output similar to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;scott             341   0.0  0.3  2502924  12828   ??  S     1:41pm   0:04.75 /System/Library/PrivateFrameworks/IMCore.framework/imagent.app/Contents/MacOS/imagent
scott           23666   0.0  0.0  2432772    460 s003  R+    9:25am   0:00.00 grep imagent
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The number you’re looking for is 341, which is the process ID of &lt;code&gt;imagent&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kill -9 341
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the process will be restarted, allowing you to change status to online.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>SQLSplitter</title>
    
    <link href="https://dor.ky/sqlsplitter/" rel="alternate" type="text/html"/>
    
    <updated>2014-10-21T17:36:32-00:00</updated>
    <id>https://dor.ky/sqlsplitter/</id>
    <content type="html">&lt;p&gt;If you need to split an SQL file into smaller chunks, I found this little utility called sqlsplitter that will do exactly that. You can download it from &lt;a href=&quot;http://rodo.nl/index.php?page=mysql-splitter&quot;&gt;http://rodo.nl/index.php?page=mysql-splitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pretty simple use, stick your SQL file into a directory along with the executable and then run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sqlsplitter your-sql-filename.sql 5000000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where 5000000 is the number of bytes you want to split files into.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Using VMware vSphere/ESXi as a Provider for Vagrant</title>
    
    <link href="https://dor.ky/using-vmware-vsphereesxi-as-a-provider-for-vagrant/" rel="alternate" type="text/html"/>
    
    <updated>2014-10-11T16:05:48-00:00</updated>
    <id>https://dor.ky/using-vmware-vsphereesxi-as-a-provider-for-vagrant/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;&lt;em&gt;Please note: This post assumes you are comfortable with Vagrant, Virtualisation and generic admin tasks on a server.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;vsphere-%26-esxi&quot;&gt;vSphere &amp;amp; ESXi&lt;/h2&gt;
&lt;p&gt;One thing I’ve been wanting to do for a while was control my &lt;a href=&quot;http://www.vmware.com/uk/products/vsphere-hypervisor&quot;&gt;VMWare ESXi&lt;/a&gt; based hosts with &lt;a href=&quot;https://www.vagrantup.com/&quot;&gt;Vagrant&lt;/a&gt;, so that I could easily create and remove boxes while testing. By default, Vagrant can’t do this. Similar to how the interaction with &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-use-digitalocean-as-your-provider-in-vagrant-on-an-ubuntu-12-10-vps&quot;&gt;Digital Ocean&lt;/a&gt; works, you can install a plugin to aid in getting this to work.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/nsidc/vagrant-vsphere/&quot;&gt;vagrant-vsphere&lt;/a&gt; plugin has been created by the &lt;a href=&quot;http://nsidc.org/&quot;&gt;National Snow and Ice Data Center&lt;/a&gt; team and open sourced for others to use. You can read more information about it on the Github page for the project at &lt;a href=&quot;https://github.com/nsidc/vagrant-vsphere/&quot;&gt;github.com/nsidc/vagrant-vsphere/&lt;/a&gt;. There are more configuration options that I don’t mention here that you can tinker with once you are more familiar with how the setup works.&lt;/p&gt;
&lt;p&gt;To start, grab the ISO file of your distribution of choice. I chose to go with Ubuntu 14.04 as it is an LTS version and more recently the projects I’ve been working on have used it. You’re going to create a Virtual Machine that will serve as a base for all of your Vagrant instances that you’ll create in future.&lt;/p&gt;
&lt;p&gt;Upload the &lt;a href=&quot;http://www.ubuntu.com/download/server&quot;&gt;Ubuntu ISO&lt;/a&gt; to your datastore and remember where you placed it. Next, create a new virtual machine with a reasonable amount of RAM and CPUs for your box, select the ISO in the CDROM options and boot up your new virtual machine as normal. Set up the box as you usually would do, I left pretty much everything as default apart from the user which you’ll need to setup for &lt;code&gt;Vagrant&lt;/code&gt; to use.&lt;/p&gt;
&lt;p&gt;During the install you will be prompted to create a user account. Use the username &lt;code&gt;vagrant&lt;/code&gt; and the password &lt;code&gt;vagrant&lt;/code&gt;, this is required for vagrant to run later down the line.&lt;/p&gt;
&lt;p&gt;Complete the installation process, installing any additional software that you would like such as Nginx, Apache, MySQL etc.&lt;/p&gt;
&lt;p&gt;After the machine has rebooted, login and run the update commands:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get update -y
sudo apt-get upgrade -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install all the updates and then reboot:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo shutdown -r now
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, install the open-vm-tools package which provides VMWare integration for the guest:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install open-vm-tools -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, after they’re installed, reboot:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo shutdown -r now
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, you need to add the &lt;code&gt;vagrant&lt;/code&gt; user to the sudoers file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo su -
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enter the &lt;code&gt;vagrant&lt;/code&gt; user password that you set to &lt;code&gt;vagrant&lt;/code&gt; earlier and then run the following command to edit the sudoers for the machine:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;visudo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the end of the file, add the line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vagrant ALL=(ALL) NOPASSWD:ALL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Exit the editor by pressing CTRL+X, Save changes. Next we need to add Vagrants key to the user account:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p /home/vagrant/.ssh
wget --no-check-certificate https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub -O /home/vagrant/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the file has downloaded, reset permissions to the correct ones:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chmod 0700 /home/vagrant/.ssh
chmod 0600 /home/vagrant/.ssh/authorized_keys
chown -R vagrant /home/vagrant/.ssh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we’ll need to install the OpenSSH server (if you haven’t already):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install -y openssh-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After installation is complete, edit the configuration file at &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; and make sure that following options match the below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Port 22
PubKeyAuthentication yes
AuthorizedKeysFile %h/.ssh/authorized_keys
PermitEmptyPasswords no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restart the SSH server:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo service ssh restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we have our template box. In your vSphere client, right click on your newly created virtual machine, select Template, then select “Clone to Template”. Follow the steps and give it a good name that you’ll remember.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/content/images/2014/Oct/vmware_vagrant-1.png&quot; alt=&quot;Creating a Template in vSphere&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you can see in the image above, I called mine &lt;code&gt;ubuntu.template.dc.sw10.net&lt;/code&gt; which is sitting in the resource pool &lt;code&gt;Linux&lt;/code&gt; in the host &lt;code&gt;192.168.1.2&lt;/code&gt; and that host resides in the datacentre &lt;code&gt;dc.sw10.net&lt;/code&gt;. This is just a sample configuration and you can adjust yours to suit.&lt;/p&gt;
&lt;h2 id=&quot;installing-the-vagrant-plugin&quot;&gt;Installing the Vagrant Plugin&lt;/h2&gt;
&lt;p&gt;If you’ve got this far, I’m going to assume that you have Vagrant installed on your on your machine. Run the following command to install the plugin that we’re going to use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vagrant plugin install vagrant-vsphere
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can learn more about the plugin and it’s various options over on the Github page at &lt;a href=&quot;https://github.com/nsidc/vagrant-vsphere/&quot;&gt;github.com/nsidc/vagrant-vsphere/&lt;/a&gt;. There are quite a few settings that you can change which I won’t detail here.&lt;/p&gt;
&lt;h2 id=&quot;creating-a-vagrantfile&quot;&gt;Creating a Vagrantfile&lt;/h2&gt;
&lt;p&gt;To create a &lt;code&gt;Vagrantfile&lt;/code&gt; that we can run, we’ll need to add a few configuration options in to instruct the plugin on where to locate things. I started with the following &lt;code&gt;Vagrantfile&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Vagrant.configure(&amp;quot;2&amp;quot;) do |config|
  config.vm.box = &#39;vsphere&#39;
  config.vm.box_url = &#39;https://vagrantcloud.com/ssx/boxes/vsphere-dummy/versions/1/providers/vsphere.box&#39;

  config.vm.provider :vsphere do |vsphere|
    # The host we&#39;re going to connect to
    vsphere.host = &#39;192.168.1.253&#39;                            

   # The host for the new VM
    vsphere.compute_resource_name = &#39;192.168.1.2&#39;            

    # The resource pool for the new VM
    vsphere.resource_pool_name = &#39;Linux&#39;                    

    # The template we&#39;re going to clone        
    vsphere.template_name = &#39;ubuntu.template.dc.sw10.net&#39;    

    # The name of the new machine
    vsphere.name = &#39;bingo&#39;                                     

    # vSphere login
    vsphere.user = &#39;root&#39;                                    

    # vSphere password
    vsphere.password = &#39;password&#39;                            

    # If you don&#39;t have SSL configured correctly, set this to &#39;true&#39;
    vsphere.insecure = true                                    
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save that file, double check your credentials and then run &lt;code&gt;Vagrant&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; vagrant up --provider=vsphere
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see progress in the task/event log in vSphere, but you should see the template being cloned and then the machine booting:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/content/images/2014/Oct/vmware_vagrant_clone.png&quot; alt=&quot;vSphere showing created VM and clone in operation&quot;&gt;&lt;/p&gt;
&lt;p&gt;After this has completed, you’ll have something similar to the following output where you ran &lt;code&gt;vagrant up&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ➜  vagrant up --provider=vsphere     
 Bringing machine &#39;default&#39; up with &#39;vsphere&#39; provider...
 ==&amp;gt; default: Calling vSphere CloneVM with the following settings:
 ==&amp;gt; default:  -- Template VM: dc.sw10.net/vm/ubuntu.template.dc.sw10.net
 ==&amp;gt; default:  -- Target VM: dc.sw10.net/vm/bingo
 ==&amp;gt; default: Waiting for SSH to become available...
 ==&amp;gt; default: New virtual machine successfully cloned and started
 ==&amp;gt; default: Rsyncing folder: /Users/scott/Downloads/tmp/ =&amp;gt; /vagrant
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can now use the other &lt;code&gt;Vagrant&lt;/code&gt; commands such as ssh:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;➜  tmp  vagrant ssh     
Welcome to Ubuntu 14.04.1 LTS (GNU/Linux 3.13.0-32-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

 System information disabled due to load higher than 1.0

Last login: Sat Oct 11 13:30:21 2014 from 192.168.1.3
vagrant@ubuntu:~$ hostname
ubuntu
vagrant@ubuntu:~$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and of course you can &lt;code&gt;vagrant destroy&lt;/code&gt; too:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ➜  vagrant destroy
==&amp;gt; default: Calling vSphere PowerOff    
==&amp;gt; default: Calling vSphere Destroy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ll most likely update this article soon with provisioning Nginx, PHP etc. If you need a dummy box to use with vagrant-vsphere, then I’ve added one to &lt;a href=&quot;https://vagrantcloud.com/&quot;&gt;Vagrant Cloud&lt;/a&gt; at:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://vagrantcloud.com/ssx/boxes/vsphere-dummy/versions/1/providers/vsphere.box&quot;&gt;https://vagrantcloud.com/ssx/boxes/vsphere-dummy/versions/1/providers/vsphere.box&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>OSX: Format an Encrypted Drive</title>
    
    <link href="https://dor.ky/osx-format-an-encrypted-drive/" rel="alternate" type="text/html"/>
    
    <updated>2014-09-23T20:21:20-00:00</updated>
    <id>https://dor.ky/osx-format-an-encrypted-drive/</id>
    <content type="html">&lt;p&gt;If you need to format an encrypted disk on OSX, you’ll need to use the command line &lt;code&gt;diskutil&lt;/code&gt; as Disk Utility won’t let you do anything with the device.&lt;/p&gt;
&lt;p&gt;First, find the ID of the disk you wish to format, using:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;diskutil list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will list your disks, for example I wish to format the 2TB drive, I’d use &lt;code&gt;disk2&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/dev/disk0
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *250.1 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                  Apple_HFS Macintosh HD            249.2 GB   disk0s2
   3:                 Apple_Boot Recovery HD             650.0 MB   disk0s3
/dev/disk1
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk1
   1:                        EFI EFI                     209.7 MB   disk1s1
   2:                  Apple_HFS Data                    477.0 GB   disk1s2
   3:                  Apple_HFS Scott                   522.8 GB   disk1s3
/dev/disk2
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *2.0 TB     disk2
   1:                        EFI EFI                     209.7 MB   disk2s1
   2:                  Apple_HFS Time Machine            2.0 TB     disk2s2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then go ahead and format the drive (remember this will format your drive and &lt;strong&gt;&lt;em&gt;remove all data&lt;/em&gt;&lt;/strong&gt; from the disk):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;diskutil eraseDisk JHFS+ Test disk2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace the label Test with the name you wish to give the new partition. After you’ve done this, you can edit the disk normally with Disk Utility.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Install Mailcatcher on Laravel Homestead</title>
    
    <link href="https://dor.ky/install-mailcatcher-on-laravel-homestead/" rel="alternate" type="text/html"/>
    
    <updated>2014-09-20T19:34:09-00:00</updated>
    <id>https://dor.ky/install-mailcatcher-on-laravel-homestead/</id>
    <content type="html">&lt;h4&gt;Update – October 18th 2014:&lt;/h4&gt;
&lt;p&gt;The wonderful &lt;a href=&quot;http://twitter.com/fideloper&quot;&gt;Chris Fidao&lt;/a&gt; noted in the comments that if you’re not using &lt;a href=&quot;http://laravel.com/docs/4.2/homestead&quot;&gt;Laravel Homestead&lt;/a&gt; and are using a different box, you may need to install the &lt;code&gt;build-essential&lt;/code&gt; package too. You can do that with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install build-essential
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that’s installed the instructions below should be fine.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you’re looking to debug outbound email easily, then &lt;a href=&quot;http://mailcatcher.me/&quot;&gt;mailcatcher&lt;/a&gt; will be a life saver for you. It’ll give you a nice interface to view outbound emails:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://f.cl.ly/items/3w2T1p0F3g003b2i1F2z/Screen%20shot%202011-06-23%20at%2011.39.03%20PM.png&quot; alt=&quot;Mailcatcher&quot;&gt;&lt;/p&gt;
&lt;p&gt;To install it, ssh to your box and follow these steps:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install ruby-dev libsqlite3-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that’s installed, you can install the gem with this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo gem install mailcatcher
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After mailcatcher is installed, you can run the program with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mailcatcher --http-ip 0.0.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’ve using Vagrant then you’ll need to forward port 1080 from the guest to the host machine as well.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Add Logfile to Memcache/Memcached Daemon on Linux</title>
    
    <link href="https://dor.ky/add-logfile-to-memcachememcached-daemon-on-linux/" rel="alternate" type="text/html"/>
    
    <updated>2014-09-11T22:34:55-00:00</updated>
    <id>https://dor.ky/add-logfile-to-memcachememcached-daemon-on-linux/</id>
    <content type="html">&lt;p&gt;If you need to add a log file for &lt;code&gt;memcache&lt;/code&gt; to help debug an issue, you can either use the following syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;memcached -d -m 3072 -l localhost -p 11211 -u nobody -v 2&amp;gt;&amp;gt;/tmp/memcached.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or if you’re on RHEL/CentOS, you can edit the file &lt;code&gt;/etc/sysconfig/memcached&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PORT=&amp;quot;11211&amp;quot;
USER=&amp;quot;memcached&amp;quot;
MAXCONN=&amp;quot;3048&amp;quot;
CACHESIZE=&amp;quot;256&amp;quot;
OPTIONS=&amp;quot;-vv &amp;gt;&amp;gt; /var/log/memcached 2&amp;gt;&amp;amp;1&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save the file, restart memcache and you’ll have a log file. This was taken from this &lt;a href=&quot;http://serverfault.com/questions/208538/how-to-specify-the-log-file-for-memcached-on-rhel-centos&quot;&gt;StackOverflow question&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Windows: Add user to group via Command Line</title>
    
    <link href="https://dor.ky/windows-add-user-to-group-via-command-line/" rel="alternate" type="text/html"/>
    
    <updated>2014-09-10T17:47:19-00:00</updated>
    <id>https://dor.ky/windows-add-user-to-group-via-command-line/</id>
    <content type="html">&lt;p&gt;I recently had to fix a Windows machine that had a broken user profile and needed to add the new user to the admin group.&lt;/p&gt;
&lt;p&gt;A few Google searches later and this is the command to run in the command line prompt:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;net localgroup group user /add
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can find this and more syntaxes at the helpful &lt;a href=&quot;http://www.windows-commandline.com/add-user-to-group-from-command-line/&quot;&gt;windows-commandline.com&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Slack Beta for Mac with Multiple Team Support</title>
    
    <link href="https://dor.ky/slack-beta-for-mac-with-multiple-team-support/" rel="alternate" type="text/html"/>
    
    <updated>2014-09-07T21:44:48-00:00</updated>
    <id>https://dor.ky/slack-beta-for-mac-with-multiple-team-support/</id>
    <content type="html">&lt;p&gt;If you’re a &lt;a href=&quot;https://slack.com/&quot;&gt;Slack&lt;/a&gt; user (and you should be) and wish to use the Mac app, it’s a bit tedious for those of us who are in multiple teams. They’ve recently released a beta version that has support for multiple teams in a much better interface.&lt;/p&gt;
&lt;p&gt;You can download it from HockeyApp at this URL:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://rink.hockeyapp.net/apps/06bd6493684f65a3b8f47aca92c9006e&quot;&gt;https://rink.hockeyapp.net/apps/06bd6493684f65a3b8f47aca92c9006e&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Syncable Host File to Make the Internet Suck Less</title>
    
    <link href="https://dor.ky/syncable-host-file-to-make-the-internet-suck-less/" rel="alternate" type="text/html"/>
    
    <updated>2014-08-20T21:05:16-00:00</updated>
    <id>https://dor.ky/syncable-host-file-to-make-the-internet-suck-less/</id>
    <content type="html">&lt;p&gt;We’ve all been there. A friend sends you a link to an internet shock site. If you’re familiar with the &lt;code&gt;hosts&lt;/code&gt; file on your machine, then you can use this large sync-able list to compliment your own rules. If you using a Mac, you can use the nifty &lt;a href=&quot;http://www.clockwise.ee/gasmask/&quot;&gt;Gas Mask&lt;/a&gt; program to edit your hosts file without having to jump into a shell.&lt;/p&gt;
&lt;p&gt;URL for the hosts file is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://someonewhocares.org/hosts/hosts 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As well as IPv6 files, there are a few other formats available as well.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Virtualmin &amp;#8211; FTP/SFTP File Writing Errors</title>
    
    <link href="https://dor.ky/virtualmin-ftpsftp-file-writing-errors/" rel="alternate" type="text/html"/>
    
    <updated>2014-08-19T20:58:36-00:00</updated>
    <id>https://dor.ky/virtualmin-ftpsftp-file-writing-errors/</id>
    <content type="html">&lt;p&gt;If you’re using Virtualmin on your servers and have a few odd FTP error messages (happened for me using SFTP too), then it’s one of three things.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Disk quota for the hosting account has exceeded&lt;/li&gt;
&lt;li&gt;Server has ran out of memory&lt;/li&gt;
&lt;li&gt;The configuration options below need to be set in &lt;code&gt;/etc/proftpd.conf&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As mentioned above, I found that these two options added into &lt;code&gt;/etc/proftpd.conf&lt;/code&gt; fixed the file write issue in some cases:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;AllowRetrieveRestart on
AllowStoreRestart on
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Useful Notes for phpinfo() &amp;#038; Capturing Output of phpinfo()</title>
    
    <link href="https://dor.ky/useful-notes-for-phpinfo-capturing-output/" rel="alternate" type="text/html"/>
    
    <updated>2014-08-16T20:44:45-00:00</updated>
    <id>https://dor.ky/useful-notes-for-phpinfo-capturing-output/</id>
    <content type="html">&lt;p&gt;I recently needed to capture the output of phpinfo() for a to a log upon install. I’d been able to do this in the past but couldn’t quite remember how I managed it. This is where &lt;code&gt;ob_start()&lt;/code&gt; and &lt;code&gt;ob_flush()&lt;/code&gt; come into their own.&lt;/p&gt;
&lt;p&gt;To get the contents of phpinfo(); into a variable, you can use the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ob_start();
phpinfo();
$strPhpInfo = ob_get_contents();
ob_clean();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The variable &lt;code&gt;$strPhpInfo&lt;/code&gt; will now contain the output from phpinfo().&lt;/p&gt;
&lt;p&gt;A side note, if you only want the variables section of phpinfo(), then use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;phpinfo(32);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and it’ll give you just that in the output. You can read more about the other values you can pass to &lt;code&gt;phpinfo()&lt;/code&gt; at &lt;a href=&quot;http://php.net/manual/en/function.phpinfo.php&quot;&gt;php.net/manual/en/function.phpinfo.php&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>PHP ActiveRecord &amp;#8211; Get Last Query</title>
    
    <link href="https://dor.ky/php-activerecord-get-last-query/" rel="alternate" type="text/html"/>
    
    <updated>2014-08-15T21:17:14-00:00</updated>
    <id>https://dor.ky/php-activerecord-get-last-query/</id>
    <content type="html">&lt;p&gt;I recently had to do some work on an older site that used the PHP implementation of &lt;a href=&quot;http://www.phpactiverecord.org/&quot;&gt;ActiveRecord&lt;/a&gt;. One of the issues I had was that the queries being ran weren’t produced the expected result. I found two commands to help with this an issue the last run query:&lt;/p&gt;
&lt;p&gt;If you’re within a model, you can do:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo self::connection()-&amp;gt;last_query;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and if you’re outside your model, you can use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo model::connection()-&amp;gt;last_query;
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Install Old Version of Laravel 4.1.X for PHP 5.3 Servers using Composer</title>
    
    <link href="https://dor.ky/install-old-version-of-laravel-4-1-x-for-php-5-3-servers-using-composer/" rel="alternate" type="text/html"/>
    
    <updated>2014-08-10T21:23:38-00:00</updated>
    <id>https://dor.ky/install-old-version-of-laravel-4-1-x-for-php-5-3-servers-using-composer/</id>
    <content type="html">&lt;p&gt;If you need to install an older version of Laravel for use with a server that has PHP 5.3.X for example, you can do so using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;composer create-project laravel/laravel project-directory 4.1.*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is useful when you can’t upgrade the version of PHP but still wish to use Laravel.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Almost Time for Amsterdam!</title>
    
    <link href="https://dor.ky/almost-time-for-amsterdam/" rel="alternate" type="text/html"/>
    
    <updated>2014-08-09T14:16:30-00:00</updated>
    <id>https://dor.ky/almost-time-for-amsterdam/</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/content_old/laracon_eu_2013.jpg&quot; alt=&quot;Preparing for Laracon EU 2013&quot;&gt;&lt;/p&gt;
&lt;p&gt;It’s a couple of weeks away until I head off for Amsterdam.&lt;/p&gt;
&lt;p&gt;I’ll arrive in Amsterdam on the 25th August of August and depart on the&lt;br&gt;
31st. I’ll be in Amsterdam to attend the fantastic&lt;br&gt;
&lt;a href=&quot;http://laracon.eu/2014/&quot;&gt;Laracon EU&lt;/a&gt; conference along with a work colleague.&lt;/p&gt;
&lt;p&gt;We’re currently in the process of making plans of what to do while&lt;br&gt;
we’re there, we got a lot of the common tourist things done last year, so&lt;br&gt;
this year it’ll be good to see some new places.&lt;/p&gt;
&lt;p&gt;If you have experience of renting a boat of in the &#39;dam too, I’d like a chat.&lt;/p&gt;
&lt;p&gt;If you’ve got any suggestions, leave them in the comments below. If you&lt;br&gt;
know anyone in Amsterdam with good local knowledge, point them in the direction&lt;br&gt;
of this post too!&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Interactivity for Payment Forms</title>
    
    <link href="https://dor.ky/interactivity-for-payment-forms/" rel="alternate" type="text/html"/>
    
    <updated>2014-07-26T13:41:13-00:00</updated>
    <id>https://dor.ky/interactivity-for-payment-forms/</id>
    <content type="html">&lt;p&gt;Interactivity for Payment Forms&lt;/p&gt;
&lt;p&gt;A short while ago now I read an article by Michael Villar of Stripe on using animations when users are completing payment forms.&lt;/p&gt;
&lt;p&gt;Villar put forward the argument that this improves the user experience.&lt;/p&gt;
&lt;p&gt;Below is a demonstration of doing that.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel: Filter Every Array Element with a Closure</title>
    
    <link href="https://dor.ky/laravel-filter-every-array-element-with-a-closure/" rel="alternate" type="text/html"/>
    
    <updated>2014-07-24T21:37:56-00:00</updated>
    <id>https://dor.ky/laravel-filter-every-array-element-with-a-closure/</id>
    <content type="html">&lt;p&gt;I always forget about how awesome &lt;a href=&quot;http://laravel.com/api/source-class-Illuminate.Support.Collection.html#182&quot;&gt;Laravel Collection’s&lt;/a&gt; are. I came across this gem when needing to run a filter on every element of an array. I think it may of been &lt;a href=&quot;http://daylerees.com/codebright/eloquent-collections&quot;&gt;Dayle’s book&lt;/a&gt; that first informed me of them. For example, if you have an array of fruits that you want to filter down, you can do the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Create an array of fruits
$array = [&amp;quot;banana&amp;quot;, &amp;quot;apple&amp;quot;, &amp;quot;orange&amp;quot;];

// Transform the array into a Collection object
$collection = new IlluminateSupportCollection($array);

// We don&#39;t like banana&#39;s anymore, so we&#39;re going to filter them out
$no_bananas = $collection-&amp;gt;filter(function($element) {
    if ($element != &amp;quot;banana&amp;quot;) return true;
});

// Dump out our array now, and we&#39;ll see the banana&#39;s are gone
dd($no_bananas);
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laracon US 2014</title>
    
    <link href="https://dor.ky/laracon-us-2014/" rel="alternate" type="text/html"/>
    
    <updated>2014-07-17T22:04:31-00:00</updated>
    <id>https://dor.ky/laracon-us-2014/</id>
    <content type="html">&lt;p&gt;If you haven’t noticed yet, the Laracon US 2014 videos have been posted online for a short while now, you can grab them over on Userscape’s website at &lt;a href=&quot;http://userscape.com/laracon/2014/&quot;&gt;http://userscape.com/laracon/2014/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One talk of note, which I’ve recommended to a lot of people is by Greg Baugues, titled “Devs and Depression”.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Adding Google Sitemap&#39;s to Ghost Blogging Platform</title>
    
    <link href="https://dor.ky/adding-google-sitemaps-to-ghost-blogging-platform/" rel="alternate" type="text/html"/>
    
    <updated>2014-07-16T19:06:57-00:00</updated>
    <id>https://dor.ky/adding-google-sitemaps-to-ghost-blogging-platform/</id>
    <content type="html">&lt;p&gt;I recently wanted to replace my statically generated sitemap.xml file with a dynamically one generated by &lt;a href=&quot;http://ghost.org/&quot;&gt;ghost&lt;/a&gt;. It ended up being pretty trivial to do, but the following two links helped immensely. At present, it’s a hack to the core which you’ll have to repeat if you upgrade – but that’s a small price to pay for having your sitemap generated dynamically.&lt;/p&gt;
&lt;p&gt;For adding sitemap support:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://tstrimple.com/hacking-ghost-adding-dynamic-sitemap-xml/&quot;&gt;http://tstrimple.com/hacking-ghost-adding-dynamic-sitemap-xml/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For updating the format/count:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.mathachew.com/blog/customizing-your-dynamic-sitemap-in-ghost/&quot;&gt;http://www.mathachew.com/blog/customizing-your-dynamic-sitemap-in-ghost/&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>MariaDB: Set Maximum Server Connections via Query</title>
    
    <link href="https://dor.ky/mariadb-set-maximum-server-connections-via-query/" rel="alternate" type="text/html"/>
    
    <updated>2014-06-28T20:17:30-00:00</updated>
    <id>https://dor.ky/mariadb-set-maximum-server-connections-via-query/</id>
    <content type="html">&lt;p&gt;If you’re a MariaDB user and need to set the max_connections variable a little higher while the server is running, you can use the following SQL query:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# This will give you the current mac_connections setting
select @@max_connections;

# Set the maximum connections allow for MariaDB
set global max_connections = 200;

# To see that the variable has been changed, run the following query again:  
select @@max_connections;
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>ncftp: Recursive File Get</title>
    
    <link href="https://dor.ky/ncftp-recursive-file-get/" rel="alternate" type="text/html"/>
    
    <updated>2014-06-18T21:29:55-00:00</updated>
    <id>https://dor.ky/ncftp-recursive-file-get/</id>
    <content type="html">&lt;p&gt;A while ago I wrote a post about using the basic ftp command to recursively fetch remote FTP files, it seems this doesn’t completely fetch them recursively. A great little program called &lt;a href=&quot;http://www.ncftp.com/&quot;&gt;NCFTP&lt;/a&gt; will do this accurate and pretty quickly. Install &lt;a href=&quot;http://www.ncftp.com/&quot;&gt;NCFTP&lt;/a&gt; if you haven’t already, then run the program:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ncftp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will give you a prompt, at which type the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set save-passwords yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will allow the program to save your password while its working and transferring files. Open a connection to your FTP server by using the following at the command prompt:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;open -u ftp_username ftp_host
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’ll ask for a password, enter it and then it’ll go away and connect. To then download your files recursively, enter the command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bgget -r file/path
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and once you’ve finished queuing files, type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bgstart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to begin the transfer and &lt;a href=&quot;http://www.ncftp.com/&quot;&gt;NCFTP&lt;/a&gt; will go ahead and download all your queued files.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Titanium: Remove All Children of View</title>
    
    <link href="https://dor.ky/titanium-remove-all-children-of-view/" rel="alternate" type="text/html"/>
    
    <updated>2014-06-06T21:04:27-00:00</updated>
    <id>https://dor.ky/titanium-remove-all-children-of-view/</id>
    <content type="html">&lt;p&gt;I picked up this function somewhere a while ago, it’s useful when you want to remove all the children elements of a view in Titanium.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function removeAllChildren(obj) {
    var c = obj.children.slice(0);
    for (var i = 0; i &amp;lt; c.length; ++i) {
        obj.remove(c[i]);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Apple Swift Programming Language Manual Download</title>
    
    <link href="https://dor.ky/apple-swift-programming-language-manual-download/" rel="alternate" type="text/html"/>
    
    <updated>2014-06-02T20:47:41-00:00</updated>
    <id>https://dor.ky/apple-swift-programming-language-manual-download/</id>
    <content type="html">&lt;p&gt;After Apple’s impressive WWDC keynote earlier, you can download the reference manual for the Swift programming language for iBooks using the following URL:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://itunes.apple.com/gb/book/swift-programming-language/id881256329?mt=11&quot;&gt;https://itunes.apple.com/gb/book/swift-programming-language/id881256329?mt=11&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Linux: Find All Modified Files in Last X Days</title>
    
    <link href="https://dor.ky/linux-find-all-modified-files-in-last-x-days/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-30T14:24:33-00:00</updated>
    <id>https://dor.ky/linux-find-all-modified-files-in-last-x-days/</id>
    <content type="html">&lt;p&gt;Nifty linux command to remember:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ find . -mtime -3 -ls /
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will display all the files modified in the last 3 days. You can change 3 to suit as many days as you require.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Detect Version of CS Cart Websites</title>
    
    <link href="https://dor.ky/how-to-detect-version-of-cs-cart-websites/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-27T21:59:00-00:00</updated>
    <id>https://dor.ky/how-to-detect-version-of-cs-cart-websites/</id>
    <content type="html">&lt;p&gt;Quick tip, if you need to find the version of a CS Cart based website, simply append &lt;code&gt;?version&lt;/code&gt; to the query string, so for example if you shop name is &lt;code&gt;mysupershop.co.uk&lt;/code&gt;, point your browser at:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://www.mysupershop.co.uk/index.php?version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll be presented with a page that notifies you which version of CS Cart is installed and running, similar to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CS-CART: version 2.1.4 PROFESSIONAL
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel London Meetup</title>
    
    <link href="https://dor.ky/laravel-london-meetup/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-24T12:12:32-00:00</updated>
    <id>https://dor.ky/laravel-london-meetup/</id>
    <content type="html">&lt;p&gt;On the 15th May, a work colleague and I attended Laravel London for a couple of talks by Aussie &lt;a href=&quot;https://twitter.com/kirkbushell&quot;&gt;Kirk Bushell&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/msurguy&quot;&gt;Maks Surguy&lt;/a&gt;. Both were great presentations, Kirk spoke about abstracting validation away to use across your application and Maks spoke about the pitfalls of ajax file uploads.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/laravel_london.jpg&quot; alt=&quot;Laravel London Meetup&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you’re interested in attending one of the meetups you can find the group on &lt;a href=&quot;http://meetup.com/&quot;&gt;Meetup.com&lt;/a&gt; at &lt;a href=&quot;http://www.meetup.com/London-Laravel/&quot;&gt;London Laravel&lt;/a&gt; which is created by the fantastic &lt;a href=&quot;https://twitter.com/jontybehr&quot;&gt;Jonty Behr&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel Homestead: Add Enviroment Variables to Nginx</title>
    
    <link href="https://dor.ky/laravel-homestead-add-enviroment-variables-to-nginx/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-24T01:08:50-00:00</updated>
    <id>https://dor.ky/laravel-homestead-add-enviroment-variables-to-nginx/</id>
    <content type="html">&lt;p&gt;If you wish to set your environment by using server environmental variables with the new Laravel Homestead you can do the following:&lt;/p&gt;
&lt;p&gt;Edit the website configuration name, by running the following command within the VM:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sudo nano /etc/nginx/sites-available/local.dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within the &lt;code&gt;location ~ .php$ {&lt;/code&gt; block, update your configuration to resemble this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;location ~ .php$ {
    fastcgi_split_path_info ^(.+.php)(/.+)$;

    fastcgi_param LARAVEL_ENVIRONMENT &amp;quot;dev&amp;quot;;

    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now restart Nginx&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sudo /etc/init.d/nginx restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, edit your &lt;code&gt;bootstrap/start.php&lt;/code&gt; file and update the method to detect environment:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$env = $app-&amp;gt;detectEnvironment(function(){
    return getenv(&amp;quot;LARAVEL_ENVIRONMENT&amp;quot;);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can set your environments per server.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>MySQL Procedure: Drop All Tables in Database</title>
    
    <link href="https://dor.ky/mysql-procedure-drop-all-tables-in-database/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-24T00:12:41-00:00</updated>
    <id>https://dor.ky/mysql-procedure-drop-all-tables-in-database/</id>
    <content type="html">&lt;p&gt;If you ever need a progmatic way to drop all tables in a database, you can use the following stored procedure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DELIMITER $$

DROP PROCEDURE IF EXISTS `drop_all_tables_from` $$

CREATE PROCEDURE `drop_all_tables_from`(IN schema_target VARCHAR(128))
BEGIN
    DECLARE table_list TEXT;

    SELECT
        GROUP_CONCAT(`TABLE_NAME`)
    INTO
        table_list

    FROM `information_schema`.`TABLES`
    WHERE
          `TABLE_SCHEMA` = schema_target;

    IF table_list IS NOT NULL THEN
        SET @drop_tables = CONCAT(&amp;quot;DROP TABLE &amp;quot;, table_list);

        PREPARE stmt FROM @drop_tables;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END IF;

END $$

DELIMITER ;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use, simply &lt;code&gt;call&lt;/code&gt; the procedure with the database name as the parameter:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CALL drop_all_tables_from(&amp;quot;database_name&amp;quot;); 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note: This will drop all tables, without confirmation for the database name provided.&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel: Prevent Sessions for Routes via a Filter</title>
    
    <link href="https://dor.ky/laravel-prevent-sessions-for-routes-via-a-filter/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-22T18:41:22-00:00</updated>
    <id>https://dor.ky/laravel-prevent-sessions-for-routes-via-a-filter/</id>
    <content type="html">&lt;p&gt;I needed to prevent Laravel from using sessions for a few API endpoints in an app, this is how I did it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Route::filter(&#39;session.remove&#39;, function()
{
    return Config::set(&#39;session.driver&#39;, &#39;array&#39;);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be used quite easily with a route or route group:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Route::group(array(
    &amp;quot;prefix&amp;quot; =&amp;gt; &amp;quot;api/v1&amp;quot;,
    &amp;quot;before&amp;quot; =&amp;gt; array(&amp;quot;session.remove&amp;quot;)
), function() {
    Route::get(&#39;/search&#39;, &#39;SearchController@getPerformSearch&#39;);
});
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Useful Slides from Laracon NYC 2014</title>
    
    <link href="https://dor.ky/useful-slides/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-18T17:38:31-00:00</updated>
    <id>https://dor.ky/useful-slides/</id>
    <content type="html">&lt;p&gt;I’d picked up a couple of the slides published for this years Laracon event in New York.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://speakerdeck.com/jeremeamia/aws-for-artisans&quot;&gt;Amazon Web Services for Artisans&lt;/a&gt; by Jeremy Lindblom&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://speakerdeck.com/jmikola/async-php-with-react&quot;&gt;Async PHP with React&lt;/a&gt; by Jeremy Mikola&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Company Unable to Fulful Your Order? Aquire It.</title>
    
    <link href="https://dor.ky/company-unable-to-fulful-your-order-aquire-it/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-18T11:58:59-00:00</updated>
    <id>https://dor.ky/company-unable-to-fulful-your-order-aquire-it/</id>
    <content type="html">&lt;p&gt;I absolutely love data and robots.&lt;/p&gt;
&lt;p&gt;I came across a story this morning while reading Reddit. An Amazon warehouse staff member had taken part in AMA sessions which you &lt;a href=&quot;http://www.reddit.com/r/IAmA/comments/25shfm/i_work_for_amazon_at_one_of_their_largest/&quot;&gt;can read here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One on the questions posed was about how much automation is present in the warehouse. The person replied with a detailed answer which included the fact that Amazon placed an order for a Kiva automation system that Kiva was unable to fulfil.&lt;/p&gt;
&lt;p&gt;Instead of going to find alternatives, &lt;a href=&quot;http://www.forbes.com/sites/markpmills/2012/03/23/amazons-kiva-robot-acquisition-is-bullish-for-both-amazon-and-american-jobs/&quot;&gt;Amazon purchased Kiva&lt;/a&gt; and now gets their orders fulfilled first and Kiva’s other customers afterwards.&lt;/p&gt;
&lt;p&gt;These Kiva robots are absolutely awesome and it turns the pickers work into a doddle.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel: Inverse Database Seeder</title>
    
    <link href="https://dor.ky/laravel-inverse-database-seeder/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-17T22:19:23-00:00</updated>
    <id>https://dor.ky/laravel-inverse-database-seeder/</id>
    <content type="html">&lt;p&gt;This is a pretty useful package to create database seed files from an existing database.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Laravel Inverse Seed Generator:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/orangehill/iseed&quot;&gt;https://github.com/orangehill/iseed&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>FOI: Vacant Commercial Properties in Newcastle under Lyme</title>
    
    <link href="https://dor.ky/foi-vacant-commercial-properties-in-newcastle-under-lyme/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-11T10:31:36-00:00</updated>
    <id>https://dor.ky/foi-vacant-commercial-properties-in-newcastle-under-lyme/</id>
    <content type="html">&lt;p&gt;A recent Freedom of Information request that I had placed at the local council has been returned. There were a few notable buildings currently vacant which I will document further soon.&lt;/p&gt;
&lt;p&gt;Below is a map detailing the currently &lt;a href=&quot;https://www.whatdotheyknow.com/request/empty_commercial_properties_in_n_2&quot;&gt;vacant commercial properties&lt;/a&gt; that are owned by Newcastle under Lyme Borough Council.&lt;/p&gt;
&lt;p&gt;Map was produced with the useful &lt;a href=&quot;http://jhere.net/&quot;&gt;jHERE mapping library&lt;/a&gt; that I’ve been wanting to use for a while now. You can find the code used to produce the map on Github at &lt;a href=&quot;https://github.com/ssx/data-foi-nulbc-4332/tree/master&quot;&gt;github.com/ssx/data-foi-nulbc-4332&lt;/a&gt; where you can fork/use it as required.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Mac OSX/iOS Tip: Add Folder of eBooks to iOS Device</title>
    
    <link href="https://dor.ky/mac-osxios-tip-add-folder-of-ebooks-to-ios-device/" rel="alternate" type="text/html"/>
    
    <updated>2014-05-05T10:49:34-00:00</updated>
    <id>https://dor.ky/mac-osxios-tip-add-folder-of-ebooks-to-ios-device/</id>
    <content type="html">&lt;p&gt;You can add a whole folder of eBooks to your iOS device by opening iTunes, select the files and then drop them onto the device name. It’ll take a few seconds to copy over (or minutes if you have a lot of books).&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Stuffing JavaScript into DNS TXT Records</title>
    
    <link href="https://dor.ky/stuffing-javascript-into-dns-txt-records/" rel="alternate" type="text/html"/>
    
    <updated>2014-04-23T22:40:36-00:00</updated>
    <id>https://dor.ky/stuffing-javascript-into-dns-txt-records/</id>
    <content type="html">&lt;p&gt;This is from the slightly interesting notebook.&lt;/p&gt;
&lt;p&gt;If you check out the &lt;code&gt;TXT&lt;/code&gt; record for &lt;code&gt;dor.ky&lt;/code&gt; you’ll see there is a record&lt;/p&gt;
&lt;p&gt;stuffed with Javascript, which will fire in a lot of whois web services.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;scott$   dig txt dor.ky @sam.ns.cloudflare.com

;; QUESTION SECTION:
;dor.ky.                IN  TXT

;; ANSWER SECTION:
dor.ky.            300 IN  TXT &amp;quot;&amp;lt;script type=&#39;text/javascript&#39;&amp;gt;alert(&#39;This is from a DNS record!&#39;);&amp;lt;/script&amp;gt;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see this firing in action over at &lt;a href=&quot;http://mxtoolbox.com/SuperTool.aspx?action=txt%3ador.ky&quot;&gt;http://mxtoolbox.com/SuperTool.aspx?action=txt%3Ador.ky&lt;/a&gt;, I’m not picking on them specifically, there were a number of online tools that were vulnerable to this.&lt;/p&gt;
&lt;p&gt;I’d be interested to see if you have any more creative ideas on what we can do with this.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Malware Detection for Linux Servers using Maldet</title>
    
    <link href="https://dor.ky/malware-detection-for-linux-servers-using-maldet/" rel="alternate" type="text/html"/>
    
    <updated>2014-04-21T13:33:30-00:00</updated>
    <id>https://dor.ky/malware-detection-for-linux-servers-using-maldet/</id>
    <content type="html">&lt;p&gt;Maldet is a malware scanner that’s useful on servers that accept file uploads. I use it especially on servers where I have WordPress sites hosted and it alerts me to the fact that people have used themes with Malware tucked away inside.&lt;/p&gt;
&lt;p&gt;You can visit the &lt;a href=&quot;https://www.rfxn.com/projects/linux-malware-detect/&quot;&gt;Maldet&lt;/a&gt; website for a more detailed description.&lt;/p&gt;
&lt;p&gt;Installation will only take a few moments and it’s a handy tool to have. It’ll also install a cronjob that will run automatically each day and alert you of any potential or found issues.&lt;/p&gt;
&lt;h2 id=&quot;fetch-the-current-version-of-maldet&quot;&gt;Fetch the current version of Maldet&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;[root@bob]#  cd /tmp
[root@bob]#  wget http://www.rfxn.com/downloads/maldetect-current.tar.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;unzip&quot;&gt;Unzip&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;[root@bob]# tar -zxvf maldetect-current.tar.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;[root@bob]# cd maldetect-*
[root@bob]# ./install.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;edit-configuration-file&quot;&gt;Edit Configuration File&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;[root@bob]# nano /usr/local/maldetect/conf.maldet
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;run-an-on-demand-maldet-scan&quot;&gt;Run an on-demand Maldet scan&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;[root@bob] maldet /home
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Lessons Learned When Building a SaaS</title>
    
    <link href="https://dor.ky/lessons-learned-when-building-a-saas/" rel="alternate" type="text/html"/>
    
    <updated>2014-04-19T14:37:58-00:00</updated>
    <id>https://dor.ky/lessons-learned-when-building-a-saas/</id>
    <content type="html">&lt;p&gt;A recent post by the &lt;a href=&quot;http://saasclub.com/&quot;&gt;saasclub.com&lt;/a&gt; newsletter had a good article in it by Clément Vouillon which was titled “9 Lessons Learned Building SaaS”. Effectively they had asked a few members of eFounders what the lessons they learned when building their services.&lt;/p&gt;
&lt;p&gt;You can read the full article at &lt;a href=&quot;http://efounders.co/9-lessons-learned-building-saas/&quot;&gt;efounders.co/9-lessons-learned-building-saas/&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>What You Should Do About the OpenSSL/Heartbleed Security Problem</title>
    
    <link href="https://dor.ky/what-you-should-do-about-the-opensslheartbleed-security-problem/" rel="alternate" type="text/html"/>
    
    <updated>2014-04-09T18:09:03-00:00</updated>
    <id>https://dor.ky/what-you-should-do-about-the-opensslheartbleed-security-problem/</id>
    <content type="html">&lt;p&gt;By now you have probably read the news and seen the warnings about the OpenSSL Heartbleed security vulnerability that is present in certain versions of the software that powers 66% of the internet.&lt;/p&gt;
&lt;p&gt;Here’s what you should now do:&lt;/p&gt;
&lt;p&gt;If you’re not a server admin then check the websites you frequently use at &lt;a href=&quot;http://filippo.io/Heartbleed/&quot;&gt;http://filippo.io/Heartbleed/&lt;/a&gt;. If the site shows as ‘seems safe’ then login and update your passwords to something secure and that you have not used before. Nearly every large tech company has recommended resetting your passwords.&lt;/p&gt;
&lt;p&gt;Read the BBC article &lt;a href=&quot;http://www.bbc.co.uk/news/technology-26954540&quot;&gt;Heartbleed Bug: Public urged to reset all passwords&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;As noted in the above BBC article:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The University of Surrey’s Prof Alan Woodward is among security experts to have suggested internet users should now update their login details.&lt;/p&gt;
&lt;p&gt;He suggests the following rules should be observed when picking a new password.&lt;/p&gt;
&lt;p&gt;Don’t choose one obviously associated with you&lt;/p&gt;
&lt;p&gt;Hackers can find out a lot about you from social media so if they are targeting you specifically and you choose, say, your pet’s name you’re in trouble.&lt;/p&gt;
&lt;p&gt;Choose words that don’t appear in a dictionary&lt;/p&gt;
&lt;p&gt;Hackers can pre-calculate the encrypted forms of whole dictionaries and easily reverse engineer your password.&lt;/p&gt;
&lt;p&gt;Use a mixture of unusual characters&lt;/p&gt;
&lt;p&gt;You can use a word or phrase that you can easily remember but where characters are substituted, eg, Myd0gha2B1g3ars!&lt;/p&gt;
&lt;p&gt;Have different passwords for different sites and systems&lt;/p&gt;
&lt;p&gt;If hackers compromise one system you do not want them having the key to unlock all your other accounts.&lt;/p&gt;
&lt;p&gt;Keep them safely&lt;/p&gt;
&lt;p&gt;With multiple passwords it is tempting to write them down and carry them around with you. Better to use some form of secure password vault on your phone.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you are a server administrator, make sure your openssl libraries are up to date using yum/rpm/apt or your package manager of choice and then test your sites using the tool above.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Tip: Apache mod_rewrite Rule Tester</title>
    
    <link href="https://dor.ky/tip-apache-mod_rewrite-rule-tester/" rel="alternate" type="text/html"/>
    
    <updated>2014-04-04T22:19:14-00:00</updated>
    <id>https://dor.ky/tip-apache-mod_rewrite-rule-tester/</id>
    <content type="html">&lt;p&gt;If you’re a &lt;a href=&quot;https://dor.ky/tag/devop/&quot;&gt;#devop&lt;/a&gt; then at some point you’ve probably had to deal with Apache’s mod_rewrite. You can find a really handy tester written by Martin Melin on his website.&lt;/p&gt;
&lt;p&gt;With his &lt;a href=&quot;http://martinmelin.se/rewrite-rule-tester/&quot;&gt;mod_rewrite tester&lt;/a&gt; you can test your rules before putting them into staging or production.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Export All Your Flickr Photos with Flump</title>
    
    <link href="https://dor.ky/export-all-your-flickr-photos-with-flump/" rel="alternate" type="text/html"/>
    
    <updated>2014-04-03T22:28:40-00:00</updated>
    <id>https://dor.ky/export-all-your-flickr-photos-with-flump/</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/content_old/flump.png&quot; alt=&quot;Flump - Flickr Image Export&quot;&gt;&lt;/p&gt;
&lt;p&gt;This year I’ve decided to not renew my Flickr Pro membership and then had to the fun task of exporting all my images.&lt;/p&gt;
&lt;p&gt;I came across this nifty Adobe Air application called Flump that will run on my Mac.&lt;/p&gt;
&lt;p&gt;You can download &lt;a href=&quot;https://code.google.com/p/onairbustour/downloads/detail?name=Flump_91.air&amp;amp;can=2&amp;amp;q=Flump&quot;&gt;Flump&lt;/a&gt; and export your own images.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Project: Parking in Southampton</title>
    
    <link href="https://dor.ky/project-parking-in-southampton/" rel="alternate" type="text/html"/>
    
    <updated>2014-04-01T18:38:00-00:00</updated>
    <id>https://dor.ky/project-parking-in-southampton/</id>
    <content type="html">&lt;p&gt;Content coming soon.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Project: Local Electronic Data</title>
    
    <link href="https://dor.ky/project-local-electronic-data/" rel="alternate" type="text/html"/>
    
    <updated>2014-04-01T18:37:22-00:00</updated>
    <id>https://dor.ky/project-local-electronic-data/</id>
    <content type="html">&lt;p&gt;Content coming soon.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Project: OAuth Examples</title>
    
    <link href="https://dor.ky/project-oauth-examples/" rel="alternate" type="text/html"/>
    
    <updated>2014-04-01T18:36:45-00:00</updated>
    <id>https://dor.ky/project-oauth-examples/</id>
    <content type="html">&lt;p&gt;Content coming soon.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Project: StokeTraffic</title>
    
    <link href="https://dor.ky/project-stoketraffic/" rel="alternate" type="text/html"/>
    
    <updated>2014-04-01T18:35:26-00:00</updated>
    <id>https://dor.ky/project-stoketraffic/</id>
    <content type="html">&lt;p&gt;Content coming soon.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>AirMail for Mac is Awesome &amp;#8211; Almost.</title>
    
    <link href="https://dor.ky/airmail-for-mac-is-awesome-almost/" rel="alternate" type="text/html"/>
    
    <updated>2014-03-30T15:14:44-00:00</updated>
    <id>https://dor.ky/airmail-for-mac-is-awesome-almost/</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/airmail.jpg&quot; alt=&quot;Airmail for Mac&quot;&gt;&lt;/p&gt;
&lt;p&gt;For a few months now I’ve been using &lt;a href=&quot;http://airmailapp.com/&quot;&gt;Airmail for Mac&lt;/a&gt; as my main email client on my home Mac and Macbook Air. The interface is fantastic and it’s lightweight too which is exactly what I wanted. The whole experience of using the app is comfortable.&lt;/p&gt;
&lt;p&gt;The problem comes however with no support for PGP/SMIME and no preference syncing across multiple computers.&lt;/p&gt;
&lt;p&gt;Sadly, this means I can’t ditch Apple Mail just yet, but if there are enough people who want these two features within Airmail, I think the developers would implement them.&lt;/p&gt;
&lt;p&gt;You can cast your vote for the features over on the Airmail help forum:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://airmail.zendesk.com/entries/37478576-Mail-Encryption-and-Signing-Support-using-GPG&quot;&gt;Airmail Support for PGP&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://airmail.zendesk.com/entries/45505967-iCloud-support-across-several-computers-and-even-Apple-Mail-&quot;&gt;iCloud Preference Syncing&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Image credit: &lt;a href=&quot;http://airmailapp.com/&quot;&gt;airmailapp.com&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laracon EU 2014</title>
    
    <link href="https://dor.ky/laracon-eu-2014-3/" rel="alternate" type="text/html"/>
    
    <updated>2014-03-28T23:34:59-00:00</updated>
    <id>https://dor.ky/laracon-eu-2014-3/</id>
    <content type="html">&lt;p&gt;Tech companies, this is your chance to get a little free advertising. I’ll be attending the wonderful &lt;a href=&quot;http://laracon.eu/2014/&quot;&gt;Laracon EU 2014&lt;/a&gt; conference in Amsterdam this year and I’ll happily wear a t-shirt from your company while I’m there.&lt;/p&gt;
&lt;p&gt;Also, if you want to provide some stickers, coupons or other promotional material for me to pass on while I’m there – I’d be happy to.&lt;/p&gt;
&lt;p&gt;Pop me an email to &lt;a href=&quot;mailto:scott@dor.ky&quot;&gt;scott@dor.ky&lt;/a&gt; and I can let you know shipping details etc.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Using Iron.io Workers for Large Scale PHP Posting with Laravel</title>
    
    <link href="https://dor.ky/using-iron-io-workers-for-large-scale-php-posting-with-laravel/" rel="alternate" type="text/html"/>
    
    <updated>2014-03-28T22:35:59-00:00</updated>
    <id>https://dor.ky/using-iron-io-workers-for-large-scale-php-posting-with-laravel/</id>
    <content type="html">&lt;p&gt;The most popular and prolific codebase I’ve created and worked with has been the best way to &lt;a href=&quot;http://tweekly.fm/&quot;&gt;post last.fm to twitter&lt;/a&gt;, the wonderful &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt;. Each day, the service publishes hundreds and thousands of social media updates to Facebook and Twitter.&lt;/p&gt;
&lt;h3 id=&quot;the-challenges-%26-self-ddosing&quot;&gt;The Challenges &amp;amp; Self-DDOSing&lt;/h3&gt;
&lt;p&gt;The biggest challenge with having a system that posts so many updates is that every time we post an update, there is a link to the users profile which is then visited and spidered. The effect this has on the website and service is massive.&lt;/p&gt;
&lt;p&gt;It’s the equivalent of a lower scale &lt;a href=&quot;http://en.wikipedia.org/wiki/Denial-of-service_attack&quot;&gt;Distributed Denial-of-Service attack&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;last.fm-help&quot;&gt;&lt;a href=&quot;http://last.fm/&quot;&gt;Last.fm&lt;/a&gt; Help&lt;/h3&gt;
&lt;p&gt;In late 2013, &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt; had become massively popular. We had users from some of the largest tech companies in the world using our service. Scalability once again became an issue. Towards the end of the year, &lt;a href=&quot;http://last.fm/&quot;&gt;Last.fm&lt;/a&gt; provided us with a beefier hosting solution which eased the load we would be under daily and allowed the service to expand.&lt;/p&gt;
&lt;h3 id=&quot;sequential-posting&quot;&gt;Sequential Posting&lt;/h3&gt;
&lt;p&gt;To alleviate the DDOS effect the first few versions of the service would post social updates sequentially with a predefined sleep between each outbound post. This worked well when there was only a few hundred users onboard but as the service grew it became impossible to post all social updates within the 24 hour period we required them to go out at.&lt;/p&gt;
&lt;h3 id=&quot;multi-curl&quot;&gt;Multi-curl&lt;/h3&gt;
&lt;p&gt;One of the first libraries that I’d used to post Twitter updates was &lt;a href=&quot;https://github.com/jmathai/twitter-async&quot;&gt;twitter-async&lt;/a&gt; by &lt;a href=&quot;http://jaisenmathai.com/&quot;&gt;Jaisen Mathai&lt;/a&gt;. This introduced me to multi-curl and then I discovered rolling-curl. Being able to post multiple tweets was a great advancement, but this brought with it an unintended consequence of amplifying the DDOS feeling for our servers.&lt;/p&gt;
&lt;p&gt;In January 2013, we moved away from our &lt;a href=&quot;http://last.fm/&quot;&gt;Last.fm&lt;/a&gt; hosted solution to a dedicated server and a dedicated database server. This allowed massive expansion for a short period of time. We quickly ended up encountering more issues with scalability and more importantly cost. Nearly 99% of our user base consists of free users that are shown advertising. We were fast heading past revenue for server costs.&lt;/p&gt;
&lt;h2 id=&quot;resolutions&quot;&gt;Resolutions&lt;/h2&gt;
&lt;p&gt;Around October 2013 I discovered &lt;a href=&quot;http://iron.io/&quot;&gt;iron.io&lt;/a&gt; almost by accident. I’d recently begun rewriting &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt; into the excellent &lt;a href=&quot;http://www.laravel.com/&quot;&gt;Laravel&lt;/a&gt; framework. I was testing &lt;a href=&quot;http://www.laravel.com/&quot;&gt;Laravel&lt;/a&gt; 4’s queuing systems and noticed a reference to &lt;a href=&quot;http://iron.io/&quot;&gt;iron.io&lt;/a&gt;. After reading more into the &lt;a href=&quot;https://www.iron.io/mq&quot;&gt;IronMQ&lt;/a&gt; product – I came across &lt;a href=&quot;https://www.iron.io/worker&quot;&gt;IronWorker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The difference &lt;a href=&quot;https://www.iron.io/worker&quot;&gt;IronWorker&lt;/a&gt; provided for &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt; cannot be understated. It allows us the create updates, package them up to be sent and then queue en-masse into an &lt;a href=&quot;https://www.iron.io/worker&quot;&gt;IronWorker&lt;/a&gt; queue. These are then processed in batches and an entire days updates can be sent out in a matter of minutes.&lt;/p&gt;
&lt;p&gt;Sunday is the busiest day of the week for &lt;a href=&quot;http://tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt;. Regularly for a year now, we’ve been pushing out over 200,000 updates. That’s 8,333 updates an hour or 138 a minute. This would take over 24 hours sequentially, around 18 hours with multiple curl calls and takes just over 40 minutes with &lt;a href=&quot;https://www.iron.io/worker&quot;&gt;IronWorker&lt;/a&gt; at a fraction of the cost.&lt;/p&gt;
&lt;p&gt;I was able to remove one of the servers and save on the hosting cost – this alone reduced our costs by half.&lt;/p&gt;
&lt;p&gt;The exceptional service, support and price is worth it alone. Mix that in with the fact costs were halved – I’m not too sure how you can look anywhere else when needing to run PHP workers for your large scale projects.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Markdown Editors for Mac OSX</title>
    
    <link href="https://dor.ky/markdown-editors-for-mac-osx/" rel="alternate" type="text/html"/>
    
    <updated>2014-03-28T20:57:15-00:00</updated>
    <id>https://dor.ky/markdown-editors-for-mac-osx/</id>
    <content type="html">&lt;p&gt;I’ve recently began to use &lt;a href=&quot;http://daringfireball.net/projects/markdown&quot;&gt;Markdown&lt;/a&gt; for almost all of my text writing needs. This includes technical notes, readme documents and &lt;a href=&quot;http://www.github.com/&quot;&gt;Github&lt;/a&gt; commits/issues/comments. Even my blog is now powered by &lt;a href=&quot;http://daringfireball.net/projects/markdown&quot;&gt;Markdown&lt;/a&gt; as I’m using &lt;a href=&quot;http://tryghost.org/&quot;&gt;Ghost&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One thing I’m missing though is a Mac based &lt;a href=&quot;http://daringfireball.net/projects/markdown&quot;&gt;Markdown&lt;/a&gt; editor. I have &lt;a href=&quot;http://www.iawriter.com/mac/&quot;&gt;iA Writer&lt;/a&gt; which I’m still happy with and that also syncs via iCloud. I’d be happier with a program that has an inbuilt preview so that I don’t have to keep opening &lt;a href=&quot;http://marked2app.com/&quot;&gt;Marked&lt;/a&gt; to see if I’ve got the formatting/flow of the document correct.&lt;/p&gt;
&lt;p&gt;I’ve just come across the highly rated &lt;a href=&quot;https://itunes.apple.com/gb/app/markdown-pro/id465965038?mt=12&quot;&gt;Markdown Pro&lt;/a&gt; and I’m thinking of giving it a try. Have you used it? Would you recommend it?&lt;/p&gt;
&lt;p&gt;If you have any suggestions , please let me know in the comments and I’ll check them out. I don’t mind paying for good, worthwhile software – I’d just like something that can fit my needs of writing and a ‘live’ preview.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Microsoft Word, Excel, Powerpoint and One Note for iPad (and free!)</title>
    
    <link href="https://dor.ky/microsoft-word-excel-powerpoint-and-one-note-for-ipad-for-free/" rel="alternate" type="text/html"/>
    
    <updated>2014-03-27T20:38:57-00:00</updated>
    <id>https://dor.ky/microsoft-word-excel-powerpoint-and-one-note-for-ipad-for-free/</id>
    <content type="html">&lt;p&gt;If you’ve missed the news today, Microsoft has finally released an iPad version of Word, Excel, Powerpoint and One Note on the app store.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Microsoft is focused on delivering the cloud for everyone, on every device. It’s a unique approach that centers on people — enabling the devices you love, work with the services you love, and in a way that works for IT and developers,”&lt;/p&gt;
&lt;p&gt;Satya Nadella, Microsoft&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was quite surprised to see that they’re free too.&lt;/p&gt;
&lt;p&gt;You can download them via the &lt;a href=&quot;https://search.itunes.apple.com/WebObjects/MZContentLink.woa/wa/link?mt=8&amp;amp;path=apps%2fmicrosoftoffice&quot;&gt;app store&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Google Apps Toolbox</title>
    
    <link href="https://dor.ky/google-apps-toolbox/" rel="alternate" type="text/html"/>
    
    <updated>2014-03-25T11:03:54-00:00</updated>
    <id>https://dor.ky/google-apps-toolbox/</id>
    <content type="html">&lt;p&gt;A neat feature I came across this week was the Google Apps toolbox. If you’re a user of Google Apps then this can be very useful to track down issues and configuration problems.&lt;/p&gt;
&lt;p&gt;The toolbox currently features a browser debugger, DNS verification and couple of log analysers.&lt;/p&gt;
&lt;p&gt;You can find the toolbox at &lt;a href=&quot;https://toolbox.googleapps.com/apps/main/&quot;&gt;https://toolbox.googleapps.com/apps/main/&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Fix Artisan Command Errors with &#39;Allowed memory size .. bytes exhausted&#39;</title>
    
    <link href="https://dor.ky/fix-artisan-command-errors-with-allowed-memory-size-bytes-exhausted/" rel="alternate" type="text/html"/>
    
    <updated>2014-03-20T19:48:18-00:00</updated>
    <id>https://dor.ky/fix-artisan-command-errors-with-allowed-memory-size-bytes-exhausted/</id>
    <content type="html">&lt;p&gt;If you encounter an error resembling the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Fatal error: Allowed memory size of 117647092 bytes exhausted (tried to allocate 14 bytes) in /home/v_102/Laravel/database/connection.php on line 192&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;PHP has run out of memory while performing Eloquent operations. The biggest cause of this is the query logging that Laravel does behind the scenes. You can either increase &lt;code&gt;memory_limit&lt;/code&gt; to a higher amount, however a better solution is to add this line before you start your database queries:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DB::disableQueryLog();
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Preparing for Laracon EU 2014</title>
    
    <link href="https://dor.ky/preparing-for-laracon-eu-2014/" rel="alternate" type="text/html"/>
    
    <updated>2014-03-20T08:04:20-00:00</updated>
    <id>https://dor.ky/preparing-for-laracon-eu-2014/</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/laracon_eu_2013.jpg&quot; alt=&quot;Preparing for Laracon EU 2013&quot;&gt;&lt;/p&gt;
&lt;p&gt;It’s the time of year again when I start to plan the summer months and the conferences I’ll be attending. Last year I attended the wonderful &lt;a href=&quot;http://laracon.eu/&quot;&gt;Laracon EU&lt;/a&gt; at &lt;a href=&quot;http://bimhuis.nl/home&quot;&gt;Bim Huis&lt;/a&gt; and it was a magnificent venue and the content of the conference was great.&lt;/p&gt;
&lt;p&gt;I’m currently in the process of planning this years trip, which I’ll be taking a few extra days before the conference to do tourist type things in Amsterdam. If you have any suggestions for places and things to do for tech minded people, let me know in the comments.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Exclude IP Address(es) from Google Analytics</title>
    
    <link href="https://dor.ky/how-to-exclude-ip-addresses-from-google-analytics/" rel="alternate" type="text/html"/>
    
    <updated>2014-01-27T11:59:53-00:00</updated>
    <id>https://dor.ky/how-to-exclude-ip-addresses-from-google-analytics/</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/google_analytics.png&quot; alt=&quot;Google Analytics&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you’re like most developers and you need to exclude yourself from showing in a Google Analytics profile, then you can set your IP address in the exclude list so that you don’t skew your analytics.&lt;/p&gt;
&lt;p&gt;To do so, login to Google Analytics, select the account your wish to edit and then click the Admin tab.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Login to Analytics&lt;/li&gt;
&lt;li&gt;Select Admin&lt;/li&gt;
&lt;li&gt;Select the Account that you wish to edit&lt;/li&gt;
&lt;li&gt;Click ‘All Filters’&lt;/li&gt;
&lt;li&gt;Click ‘New Filter’&lt;/li&gt;
&lt;li&gt;Enter name ‘Filter my IP’&lt;/li&gt;
&lt;li&gt;Select Exclude, then ‘Traffic from the IP Addresses’, then ‘that are equal to’ and enter your IP address in the boxes provided.&lt;/li&gt;
&lt;li&gt;Select the views you wish to apply this to and then click ‘Add’.&lt;/li&gt;
&lt;li&gt;Once finished, click ‘Save’.&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  
  
  <entry>
    <title>View Column Numbers in Excel instead of R1:C1 Letters</title>
    
    <link href="https://dor.ky/view-column-numbers-in-microsoft-excel-instead-of-letters/" rel="alternate" type="text/html"/>
    
    <updated>2014-01-21T10:55:24-00:00</updated>
    <id>https://dor.ky/view-column-numbers-in-microsoft-excel-instead-of-letters/</id>
    <content type="html">&lt;p&gt;Ever wanted Excel to display column numbers instead of letters (think CSV imports!):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Microsoft Excel can be configured to display column labels as numbers instead of letters. This feature is called “R1C1 Reference Style”, and though it can be useful, it can also be confusing if inadvertently enabled.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can select between the two modes quite easily. Read more at &lt;a href=&quot;https://kb.wisc.edu/page.php?id=781&quot;&gt;https://kb.wisc.edu/page.php?id=781&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Heart Internet: Switch PHP Version to 5.4 &amp; 5.5</title>
    
    <link href="https://dor.ky/heart-internet-switch-php-version-to-5-4-5-5/" rel="alternate" type="text/html"/>
    
    <updated>2014-01-09T15:54:09-00:00</updated>
    <id>https://dor.ky/heart-internet-switch-php-version-to-5-4-5-5/</id>
    <content type="html">&lt;p&gt;If you’re a &lt;a href=&quot;http://www.heartinternet.co.uk/%E2%80%8E&quot;&gt;Heart Internet&lt;/a&gt; customer and have a project that needs to run a newer version of PHP, you can add a &lt;code&gt;SetEnv&lt;/code&gt; flag to your &lt;code&gt;.htaccess&lt;/code&gt; file to switch the version on the fly.&lt;/p&gt;
&lt;p&gt;For PHP 5.5 use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SetEnv DEFAULT_PHP_VERSION 55
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For PHP 5.4 use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SetEnv DEFAULT_PHP_VERSION 54
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also switch back a version down to &lt;code&gt;5.2&lt;/code&gt; and &lt;code&gt;5.1&lt;/code&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Dump or Display SSL Certificate Information on Mac OSX/*nix</title>
    
    <link href="https://dor.ky/dump-or-display-ssl-certificate-information-on-mac-osx-nix/" rel="alternate" type="text/html"/>
    
    <updated>2013-11-16T22:02:09-00:00</updated>
    <id>https://dor.ky/dump-or-display-ssl-certificate-information-on-mac-osx-nix/</id>
    <content type="html">&lt;p&gt;The command below will display information about an SSL certificate to STDOUT.&lt;/p&gt;
&lt;pre class=&quot;theme:github lang:default decode:true&quot; title=&quot;Display SSL Certificate Information&quot;&gt;openssl x509 -in certificatefile.crt -noout -text&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>List of Amazon AWS IP Addresses for Firewall Configurations</title>
    
    <link href="https://dor.ky/list-of-amazon-aws-ip-addresses-for-firewall-configurations/" rel="alternate" type="text/html"/>
    
    <updated>2013-11-16T21:46:33-00:00</updated>
    <id>https://dor.ky/list-of-amazon-aws-ip-addresses-for-firewall-configurations/</id>
    <content type="html">&lt;p&gt;A recent project used the fantastic &lt;a href=&quot;http://iron.io/&quot;&gt;iron.io&lt;/a&gt; platform to process background jobs (highly recommended if you need to write anything at scale). Part of the task required access back across the Internet to a server behind a firewall.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://iron.io/&quot;&gt;iron.io&lt;/a&gt; platform runs on top of Amazon AWS so finding the IP addresses took a little bit of searching, but then I &lt;a href=&quot;https://forums.aws.amazon.com/ann.jspa?annID=1701&quot; target=&quot;_blank&quot;&gt;came across a forum post&lt;/a&gt; with a good list.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;US East (Northern Virginia)&lt;/strong&gt;&lt;br&gt;
72.44.32.0/19 (72.44.32.0 – 72.44.63.255)&lt;br&gt;
67.202.0.0/18 (67.202.0.0 – 67.202.63.255)&lt;br&gt;
75.101.128.0/17 (75.101.128.0 – 75.101.255.255)&lt;br&gt;
174.129.0.0/16 (174.129.0.0 – 174.129.255.255)&lt;br&gt;
204.236.192.0/18 (204.236.192.0 – 204.236.255.255)&lt;br&gt;
184.73.0.0/16 (184.73.0.0 – 184.73.255.255)&lt;br&gt;
184.72.128.0/17 (184.72.128.0 – 184.72.255.255)&lt;br&gt;
184.72.64.0/18 (184.72.64.0 – 184.72.127.255)&lt;br&gt;
50.16.0.0/15 (50.16.0.0 – 50.17.255.255)&lt;br&gt;
50.19.0.0/16 (50.19.0.0 – 50.19.255.255)&lt;br&gt;
107.20.0.0/14 (107.20.0.0 – 107.23.255.255)&lt;br&gt;
23.20.0.0/14 (23.20.0.0 – 23.23.255.255)&lt;br&gt;
54.242.0.0/15 (54.242.0.0 – 54.243.255.255)&lt;br&gt;
54.234.0.0/15 (54.234.0.0 – 54.235.255.255)&lt;br&gt;
54.236.0.0/15 (54.236.0.0 – 54.237.255.255)&lt;br&gt;
54.224.0.0/15 (54.224.0.0 – 54.225.255.255)&lt;br&gt;
54.226.0.0/15 (54.226.0.0 – 54.227.255.255)&lt;br&gt;
54.208.0.0/15 (54.208.0.0 – 54.209.255.255)&lt;br&gt;
54.210.0.0/15 (54.210.0.0 – 54.211.255.255)&lt;br&gt;
54.221.0.0/16 (54.221.0.0 – 54.221.255.255)&lt;br&gt;
54.204.0.0/15 (54.204.0.0 – 54.205.255.255)&lt;br&gt;
54.196.0.0/15 (54.196.0.0 – 54.197.255.255)&lt;br&gt;
54.198.0.0/16 (54.198.0.0 – 54.198.255.255)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;US West (Oregon)&lt;/strong&gt;&lt;br&gt;
50.112.0.0/16 (50.112.0.0 – 50.112.255.255)&lt;br&gt;
54.245.0.0/16 (54.245.0.0 – 54.245.255.255)&lt;br&gt;
54.244.0.0/16 (54.244.0.0 – 54.244.255.255)&lt;br&gt;
54.214.0.0/16 (54.214.0.0 – 54.214.255.255)&lt;br&gt;
54.212.0.0/15 (54.212.0.0 – 54.213.255.255)&lt;br&gt;
54.218.0.0/16 (54.218.0.0 – 54.218.255.255)&lt;br&gt;
54.200.0.0/15 (54.200.0.0 – 54.201.255.255)&lt;br&gt;
54.202.0.0/15 (54.202.0.0 – 54.203.255.255)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;US West (Northern California)&lt;/strong&gt;&lt;br&gt;
204.236.128.0/18 (204.236.128.0 – 204.236.191.255)&lt;br&gt;
184.72.0.0/18 (184.72.0.0 – 184.72.63.255)&lt;br&gt;
50.18.0.0/16 (50.18.0.0 – 50.18.255.255)&lt;br&gt;
184.169.128.0/17 (184.169.128.0 – 184.169.255.255)&lt;br&gt;
54.241.0.0/16 (54.241.0.0 – 54.241.255.255)&lt;br&gt;
54.215.0.0/16 (54.215.0.0 – 54.215.255.255)&lt;br&gt;
54.219.0.0/16 (54.219.0.0 – 54.219.255.255)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EU (Ireland)&lt;/strong&gt;&lt;br&gt;
79.125.0.0/17 (79.125.0.0 – 79.125.127.255)&lt;br&gt;
46.51.128.0/18 (46.51.128.0 – 46.51.191.255)&lt;br&gt;
46.51.192.0/20 (46.51.192.0 – 46.51.207.255)&lt;br&gt;
46.137.0.0/17 (46.137.0.0 – 46.137.127.255)&lt;br&gt;
46.137.128.0/18 (46.137.128.0 – 46.137.191.255)&lt;br&gt;
176.34.128.0/17 (176.34.128.0 – 176.34.255.255)&lt;br&gt;
176.34.64.0/18 (176.34.64.0 – 176.34.127.255)&lt;br&gt;
54.247.0.0/16 (54.247.0.0 – 54.247.255.255)&lt;br&gt;
54.246.0.0/16 (54.246.0.0 – 54.246.255.255)&lt;br&gt;
54.228.0.0/16 (54.228.0.0 – 54.228.255.255)&lt;br&gt;
54.216.0.0/15 (54.216.0.0 – 54.217.255.255)&lt;br&gt;
54.229.0.0/16 (54.229.0.0 – 54.229.255.255)&lt;br&gt;
54.220.0.0/16 (54.220.0.0 – 54.220.255.255)&lt;br&gt;
54.194.0.0/15 (54.194.0.0 – 54.195.255.255)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asia Pacific (Singapore)&lt;/strong&gt;&lt;br&gt;
175.41.128.0/18 (175.41.128.0 – 175.41.191.255)&lt;br&gt;
122.248.192.0/18 (122.248.192.0 – 122.248.255.255)&lt;br&gt;
46.137.192.0/18 (46.137.192.0 – 46.137.255.255)&lt;br&gt;
46.51.216.0/21 (46.51.216.0 – 46.51.223.255)&lt;br&gt;
54.251.0.0/16 (54.251.0.0 – 54.251.255.255)&lt;br&gt;
54.254.0.0/16 (54.254.0.0 – 54.254.255.255)&lt;br&gt;
54.255.0.0/16 (54.255.0.0 – 54.255.255.255)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asia Pacific (Sydney)&lt;/strong&gt;&lt;br&gt;
54.252.0.0/16 (54.252.0.0 – 54.252.255.255)&lt;br&gt;
54.253.0.0/16 (54.253.0.0 – 54.253.255.255)&lt;br&gt;
54.206.0.0/16 (54.206.0.0 – 54.206.255.255)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asia Pacific (Tokyo)&lt;/strong&gt;&lt;br&gt;
175.41.192.0/18 (175.41.192.0 – 175.41.255.255)&lt;br&gt;
46.51.224.0/19 (46.51.224.0 – 46.51.255.255)&lt;br&gt;
176.32.64.0/19 (176.32.64.0 – 176.32.95.255)&lt;br&gt;
103.4.8.0/21 (103.4.8.0 – 103.4.15.255)&lt;br&gt;
176.34.0.0/18 (176.34.0.0 – 176.34.63.255)&lt;br&gt;
54.248.0.0/15 (54.248.0.0 – 54.249.255.255)&lt;br&gt;
54.250.0.0/16 (54.250.0.0 – 54.250.255.255)&lt;br&gt;
54.238.0.0/16 (54.238.0.0 – 54.238.255.255)&lt;br&gt;
54.199.0.0/16 (54.199.0.0 – 54.199.255.255)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;South America (Sao Paulo)&lt;/strong&gt;&lt;br&gt;
177.71.128.0/17 (177.71.128.0 – 177.71.255.255)&lt;br&gt;
54.232.0.0/16 (54.232.0.0 – 54.232.255.255)&lt;br&gt;
54.233.0.0/18 (54.233.0.0 – 54.233.63.255)&lt;br&gt;
54.207.0.0/16 (54.207.0.0 – 54.207.255.255)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GovCloud&lt;/strong&gt;&lt;br&gt;
96.127.0.0/18 (96.127.0.0 – 96.127.63.255)&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Varnish Crashing Regularly on Cent OS 6.1, 6.2, 6.3 and 6.4</title>
    
    <link href="https://dor.ky/varnish-crashing-regularly-on-cent-os-6-1-6-2-6-3-and-6-4-2/" rel="alternate" type="text/html"/>
    
    <updated>2013-11-11T18:47:28-00:00</updated>
    <id>https://dor.ky/varnish-crashing-regularly-on-cent-os-6-1-6-2-6-3-and-6-4-2/</id>
    <content type="html">&lt;p&gt;Fix:&lt;/p&gt;
&lt;pre class=&quot;theme:github lang:sh decode:true&quot; title=&quot;Varnish Crashing Regularly on Cent OS 6.1, 6.2, 6.3 and 6.4&quot;&gt;echo never &amp;gt; /sys/kernel/mm/redhat_transparent_hugepage/enabled&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>jQuery Validate Method: notEqual</title>
    
    <link href="https://dor.ky/jquery-validate-method-not-equal-to/" rel="alternate" type="text/html"/>
    
    <updated>2013-11-07T20:20:58-00:00</updated>
    <id>https://dor.ky/jquery-validate-method-not-equal-to/</id>
    <content type="html">&lt;p&gt;I often have the need with jQuery validate to test whether or not a value is equal to a predetermined one. The method below provides that functionality:&lt;/p&gt;
&lt;pre class=&quot;theme:github lang:js decode:true&quot; title=&quot;jQuery Validate notEqualTo method&quot;&gt;jQuery.validator.addMethod(&quot;notEqualTo&quot;, function(v, e, p) {  
  return this.optional(e) || v != p;
}, &quot;Please specify a different value&quot;);&lt;/pre&gt;
&lt;p&gt;Which can then be used in a similar fashion to this:&lt;/p&gt;
&lt;pre class=&quot;theme:github lang:js decode:true&quot; title=&quot;Example usage of jQuery Validate notEqualTo method&quot;&gt;$(&quot;form&quot;).validate({  
  rules: {
    nameField: { notEqualTo: &quot;Placeholder Text Name&quot; }
  }
});&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Tip - Laravel 4, 500 Error on Install</title>
    
    <link href="https://dor.ky/tip-laravel-4-500-error-on-install/" rel="alternate" type="text/html"/>
    
    <updated>2013-10-29T00:19:46-00:00</updated>
    <id>https://dor.ky/tip-laravel-4-500-error-on-install/</id>
    <content type="html">&lt;p&gt;If you install &lt;a href=&quot;http://laravel.com/&quot; title=&quot;Laravel 4&quot;&gt;Laravel 4&lt;/a&gt; and you’re using Apache with a certain Virtual Host configuration (specifically using &lt;code&gt;VirtualDocumentRoot&lt;/code&gt; in my case) then you’ll need to include a &lt;code&gt;RewriteBase&lt;/code&gt; directive within the &lt;code&gt;.htaccess&lt;/code&gt; file in public/ to correct it.&lt;/p&gt;
&lt;p&gt;An example of a fixed &lt;code&gt;.htaccess&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;theme:github lang:apache mark:4 decode:true&quot; title=&quot;.htaccess to Correct 500 Errors with Laravel 4 Installations&quot;&gt;&amp;lt;IfModule mod_rewrite.c&amp;gt;  
    Options -MultiViews
    RewriteEngine On
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
&amp;lt;/IfModule&amp;gt;&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Laravel 4 Queue Names</title>
    
    <link href="https://dor.ky/laravel-4-queue-names/" rel="alternate" type="text/html"/>
    
    <updated>2013-10-26T21:49:27-00:00</updated>
    <id>https://dor.ky/laravel-4-queue-names/</id>
    <content type="html">&lt;p&gt;Just a quick note, it looks as though you can’t use a forward slash in the name of a beanstalkd queue name.&lt;/p&gt;
&lt;p&gt;Makes Laravel behaviour a little weird and random errors.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Internet Explorer, Ajax Requests and UTF-8</title>
    
    <link href="https://dor.ky/internet-explorer-ajax-requests-and-utf-8/" rel="alternate" type="text/html"/>
    
    <updated>2013-10-20T15:37:27-00:00</updated>
    <id>https://dor.ky/internet-explorer-ajax-requests-and-utf-8/</id>
    <content type="html">&lt;p&gt;While debugging a legacy application recently, I came across an ajax script that was returning the header below and failing in IE:&lt;/p&gt;
&lt;pre class=&quot;theme:github top-set:false bottom-set:false lang:php decode:true&quot; title=&quot;Incorrect IE UTF-8 Content Type&quot;&gt;Content-Type: application/json; charset=utf8&lt;/pre&gt;
&lt;p&gt;The correct header, has a dash between the UTF and 8 (correctly so):&lt;/p&gt;
&lt;pre class=&quot;theme:github top-set:false bottom-set:false lang:php decode:true&quot; title=&quot;IE UTF-8 Content Type&quot;&gt;Content-Type: application/json; charset=utf-8&lt;/pre&gt;
&lt;p&gt;Hopefully this can help someone out if they have to debug something similar.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Linux/Mac Recursive FTP Using Built-in FTP Programme</title>
    
    <link href="https://dor.ky/linux-mac-recursive-ftp-using-built-in-ftp-programme/" rel="alternate" type="text/html"/>
    
    <updated>2013-10-05T08:01:41-00:00</updated>
    <id>https://dor.ky/linux-mac-recursive-ftp-using-built-in-ftp-programme/</id>
    <content type="html">&lt;p&gt;I had to fetch a few thousand files across a few directories on a remote server recently and I was going to use NCFTP, however I’d remembered that the stock ftp program on linux can in fact do a recursive fetch. You need to remember to turn the interactive prompts off as well, because if you don’t then you will have to press the ‘Y’ key to download each file.&lt;/p&gt;
&lt;pre class=&quot;theme:github top-set:false bottom-set:false lang:sh decode:true&quot; title=&quot;FTP recursively fetch multiple files&quot;&gt;# Open connection  
ftp user@host.com

# Change directory
cd to/the/path

# Turn the interactive prompt off
prompt off

# Use the command &#39;mget&#39; to fetch the files, the glob (*) will execute
# on the remove server
mget *

# Exit cleanly
exit&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>MySQL Views are Extremely Useful</title>
    
    <link href="https://dor.ky/mysql-views-are-extremely-useful/" rel="alternate" type="text/html"/>
    
    <updated>2013-10-04T22:45:42-00:00</updated>
    <id>https://dor.ky/mysql-views-are-extremely-useful/</id>
    <content type="html">&lt;p&gt;A quick overview of using views in MySQL.&lt;/p&gt;
&lt;p&gt;First, create our products table:&lt;/p&gt;
&lt;pre class=&quot;theme:github top-set:false bottom-set:false lang:default decode:true&quot; title=&quot;Table Creation SQL&quot;&gt;CREATE TABLE `products` (  
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` text COLLATE utf8_unicode_ci,
  `price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
&lt;/pre&gt;
&lt;p&gt;Now create our users table:&lt;/p&gt;
&lt;pre class=&quot;theme:github top-set:false bottom-set:false lang:default decode:true&quot; title=&quot;User table creation SQL&quot;&gt;CREATE TABLE `users` (  
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
  `email` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;&lt;/pre&gt;
&lt;p&gt;Lastly, create our transaction table:&lt;/p&gt;
&lt;pre class=&quot;theme:github top-set:false bottom-set:false lang:default decode:true&quot; title=&quot;Transaction table creation SQL&quot;&gt;CREATE TABLE `transactions` (  
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `product_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `product_id_idx` (`product_id`),
  KEY `user_id_idx` (`user_id`),
  CONSTRAINT `product_id` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;&lt;/pre&gt;
&lt;p&gt;To query across these tables we would need to join them. A query such as:&lt;/p&gt;
&lt;pre class=&quot;theme:github top-set:false bottom-set:false lang:mysql decode:true&quot; title=&quot;SQL to query across tables&quot;&gt;SELECT  
    users.id AS UserId,
    users.name AS UserName,
    users.email AS UserEmail,
    products.id AS ProductId, 
    products.name AS ProductName, 
    products.price AS ProductPrice 

FROM transactions 

LEFT JOIN users ON (users.id = transactions.user_id) 

LEFT JOIN ON (products.id = transactions.product_id);  
&lt;/pre&gt;
&lt;p&gt;If we need to run this query often, we could simplify the process by creating a view of the above query. To create the view, we run the following SQL:&lt;/p&gt;
&lt;pre class=&quot;theme:github top-set:false bottom-set:false lang:mysql decode:true crayon-selected&quot; title=&quot;SQL to create a view&quot;&gt;USE `my_database`;

CREATE VIEW `view_transaction` AS  
    SELECT 
        users.id AS UserId, 
        users.name AS UserName, 
        users.email AS UserEmail, 
        products.id AS ProductId, 
        products.name AS ProductName, 
        products.price AS ProductPrice 

    FROM transactions 

    LEFT JOIN users ON (users.id = transactions.user_id) 

    LEFT JOIN products ON (products.id = transactions.product_id);
&lt;/pre&gt;
&lt;p&gt;Instead of then having to query against the large join, we could simply query the view:&lt;/p&gt;
&lt;pre class=&quot;theme:github top-set:false bottom-set:false lang:mysql decode:true&quot; title=&quot;Sample SQL query against a view&quot;&gt;SELECT * FROM view_transaction WHERE ProductPrice &amp;gt; 10&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>PHP Interfaces Quickstart</title>
    
    <link href="https://dor.ky/php-interfaces-quickstart/" rel="alternate" type="text/html"/>
    
    <updated>2013-09-29T18:47:50-00:00</updated>
    <id>https://dor.ky/php-interfaces-quickstart/</id>
    <content type="html">&lt;p&gt;PHP interfaces are still quite new to most. Below is a simple demonstration of their usefulness. I think I’d seen this within one of the many fantastic laravel books.&lt;/p&gt;
&lt;pre class=&quot;theme:github lang:php decode:true&quot; title=&quot;PHP Interfaces Quickstart&quot;&gt;&amp;lt;?php  
interface BillerInterface {  
    public function bill(array $user, $amount);
}
interface BillingNotifierInterface {  
    public function notify(array $user, $amount);
}


class NotifyByEmail implements BillingNotifierInterface {  
    public function notify(array $user, $amount)
    {
        echo &quot;Send email for &quot;.$user[&quot;name&quot;].&quot; of $amount&quot;.PHP_EOL;
    }
}


class NotifyByMessage implements BillingNotifierInterface {  
    public function notify(array $user, $amount)
    {
        echo &quot;Display message for &quot;.$user[&quot;name&quot;].&quot; of $amount&quot;.PHP_EOL;
    }
}


class NotifyBySMS implements BillingNotifierInterface {  
    public function notify(array $user, $amount)
    {
        echo &quot;Send SMS for &quot;.$user[&quot;name&quot;].&quot; of $amount&quot;.PHP_EOL;
    }
}


class StripeBiller implements BillerInterface {  
    public function __construct(BillingNotifierInterface $notifier)
    {
        $this-&amp;gt;notifier = $notifier;
    }

    public function bill(array $user, $amount)
    {
        // Bill the user via Stripe...
        echo &quot;Bill via Stripe&quot;.PHP_EOL;
        $this-&amp;gt;notifier-&amp;gt;notify($user, $amount);
    }
}


class PaypalBiller implements BillerInterface {  
    public function __construct(BillingNotifierInterface $notifier)
    {
        $this-&amp;gt;notifier = $notifier;
    }

    public function bill(array $user, $amount)
    {
        echo &quot;Bill via Paypal&quot;.PHP_EOL;
        $this-&amp;gt;notifier-&amp;gt;notify($user, $amount);
    }
}


class EPDQBiller implements BillerInterface {  
    public function __construct(BillingNotifierInterface $notifier)
    {
        $this-&amp;gt;notifier = $notifier;
    }


    public function bill(array $user, $amount)
    {
        echo &quot;Bill via ePDQ&quot;.PHP_EOL;
        $this-&amp;gt;notifier-&amp;gt;notify($user, $amount);
    }
}


$newBill = new StripeBiller(new NotifyBySMS);
$newBill-&amp;gt;bill(
    array(
        &quot;name&quot; =&amp;gt; &quot;Scott Wilcox&quot;
    ),
    &quot;123.89&quot;
);
$newBill = new PaypalBiller(new NotifyByMessage);
$newBill-&amp;gt;bill(
    array(
        &quot;name&quot; =&amp;gt; &quot;Scott Wilcox&quot;
    ),
    &quot;123.89&quot;
);
$newBill = new EPDQBiller(new NotifyByEmail);
$newBill-&amp;gt;bill(
    array(
        &quot;name&quot; =&amp;gt; &quot;Scott Wilcox&quot;
    ),
    &quot;123.89&quot;
);&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Handy Tip: Use an Apple plug to charge a Lumix battery</title>
    
    <link href="https://dor.ky/handy-tip-use-an-apple-plug-to-charge-a-lumix-battery/" rel="alternate" type="text/html"/>
    
    <updated>2013-09-28T09:42:00-00:00</updated>
    <id>https://dor.ky/handy-tip-use-an-apple-plug-to-charge-a-lumix-battery/</id>
    <content type="html">&lt;p&gt;Came across this tip by a work colleague the other day, if you’re a&lt;br&gt;
traveller and use Apple devices, you can use the Apple multi plug instead of&lt;br&gt;
having to carry a figure-8 cable around with you as well.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Solr, Tomcat and UTF-8</title>
    
    <link href="https://dor.ky/solr-tomcat-and-utf-8/" rel="alternate" type="text/html"/>
    
    <updated>2013-09-23T08:52:33-00:00</updated>
    <id>https://dor.ky/solr-tomcat-and-utf-8/</id>
    <content type="html">&lt;p&gt;I had to fix an issue recently where Apache Solr wasn’t returning any results for German words. After altering the schema to accommodate the German language, the same issue of being unable to search for German words was still there. It turns out that earlier version of Apache Tomcat aren’t UTF-8 enabled by default, it’s a configuration option that you need to explicitly set the URI encoding used.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Connector port=“8080” protocol=“HTTP/1.1” connectionTimeout=&amp;quot;20000&amp;quot; redirectPort=&amp;quot;8443&amp;quot; URIEncoding=&amp;quot;UTF-8&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can read more on the &lt;a href=&quot;http://wiki.apache.org/solr/SolrTomcat&quot;&gt;Tomcat Wiki&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>PHP: How to List All Functions of an Extension</title>
    
    <link href="https://dor.ky/php-how-to-list-all-functions-of-an-extension/" rel="alternate" type="text/html"/>
    
    <updated>2013-05-04T19:00:35-00:00</updated>
    <id>https://dor.ky/php-how-to-list-all-functions-of-an-extension/</id>
    <content type="html">&lt;p&gt;Recently I’ve been doing quite a lot of work that required UUID&lt;br&gt;
generation. There is two PHP libraries for generating UUID’s. One of them&lt;br&gt;
hasn’t been updated in a long, long time and the second one has absolute&lt;br&gt;
no documentation for it. After spending a few moments trying to guess the&lt;br&gt;
function names that this newly compiled extension provided, I found that PHP has&lt;br&gt;
a command called &lt;code&gt;get_extension_funcs()&lt;/code&gt; which does exactly what it says on the&lt;br&gt;
tin. It will provide you with a list of functions that an extension can provide.&lt;/p&gt;
&lt;p&gt;By running:&lt;/p&gt;
&lt;pre class=&quot;theme:github lang:php decode:true&quot;&gt;&amp;lt;?php  
echo var_dump(get_extension_funcs(&quot;uuid&quot;))  
?&amp;gt;&lt;/pre&gt;
&lt;p&gt;We get the following output:&lt;/p&gt;
&lt;img alt=&quot;get_extension_funcs&quot; src=&quot;https://dor.ky/assets/images/old_content/get_extension_funcs.png&quot;&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Tech at Christmas</title>
    
    <link href="https://dor.ky/tech-at-christmas/" rel="alternate" type="text/html"/>
    
    <updated>2013-01-14T14:01:22-00:00</updated>
    <id>https://dor.ky/tech-at-christmas/</id>
    <content type="html">&lt;p&gt;Over the holiday period this year, I decided to get a few things off my to-do list that have been sitting around for a while. I decided the contents of my Christmas geekery would be worth of a blog post and that is the one you’re reading now.&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
  Replicating Replication
&lt;/h4&gt;
&lt;p&gt;After having a number of database servers dotted around the world, with different backup systems and schedules – I finally got around to implementing replication for two of them. This will allow me to immediately roll over to the backup slaves if the main servers ever go down. The beauty of the system is that I can also run some queries on the slaves instead of the masters, which means less sluggyness for the master when I want to generate certain reports. Performance has improved for both the master (less large queries being run against it) and provides a piece of redundancy that I didn’t have previously. I’m considering doing the same for the rest of the MySQL servers I administer too. Duplicating backups of data can never be a bad thing and if one of the backups can be used for a warm start then all the better.&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
  Centralised Syslog
&lt;/h4&gt;
&lt;p&gt;Part of the reason for the large reports is that I’ve recently configured all syslog daemons to log to a centralised server. This means I can track errors more easily and also run custom queries against the syslog database with SQL instead of needing to trawl the log files. I’ve been highly impressed with the system so far and it certainly has made a big difference configuring the replication so that I can run reports against the slaves and see processes that are causing a lot of errors.&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
  Hardware
&lt;/h4&gt;
&lt;p&gt;I picked up a HTC Wildfire recently too with the aim of unlocking, rooting and replacing the bootrom within the device. I managed to succeed in doing all three of them and it wasn’t too difficult a process. The end result was an updated OS on the slightly older HTC Wildfire than was possible with their stock ROMs. The hardware for the Wildfire isn’t the best spec but the phone works fine and the OS is coming along well. I don’t think I’m interested in making the jump to Android but I’m very tempted by the Nokia Lumia 920. That’s another debate to have. The only other piece of hardware that I had flashed over Christmas was an old Fonera router, which now has &lt;a href=&quot;http://www.dd-wrt.com/&quot;&gt;dd-wrt&lt;/a&gt; and runs the wifi upstairs at home.&lt;/p&gt;
&lt;p&gt;The only other hardware related things I got done over Christmas was to replace the screen and digitiser on an iPhone 4S and the HTC Wildfire. The Wildfire screen replacement was easy, one of the easiest I’ve done. Ordering the correct part is that issue with HTC hardware for me as a large number of their phones share the same components and manufacturing identifiers. The iPhone 4S flex and power button replacement was also easy to do but as with all Apple hardware takes an age to do.&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
  PHP Projects
&lt;/h4&gt;
&lt;p&gt;There was a couple of pieces of PHP I cobbled together over the holidays too. One of the ideas for CKEditor that I had was to show a page highlight when you hover over a link, I used the &lt;a href=&quot;http://grabz.it/&quot;&gt;Grabz.it&lt;/a&gt; API to create this &lt;a href=&quot;http://lab.dor.ky/jquery-grabitz/&quot;&gt;jQuery Link Preview&lt;/a&gt;. The end result isn’t quite right yet, but its not too far off what I’m aiming for. The second project was a system for importing CSV files (although the end product could be used for anything) into a database. I wanted to provide a visual way of linking the data in the CSV against the fields in the database. Enter the domline plugin and a few pieces of knowledge from around the web (Stackoverflow user &lt;a href=&quot;http://stackoverflow.com/questions/536676/how-to-draw-a-line-between-draggable-and-droppable&quot;&gt;Bruno Alexaandre&lt;/a&gt;&amp;gt; provided most of the legwork). The end result will be a &lt;a href=&quot;http://lab.dor.ky/jquery-domline/&quot;&gt;jQuery &amp;amp; PHP CSV Importer&lt;/a&gt;. Ideas and thoughts both welcome on these projects.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>PHP: Get Accurate User IP Address</title>
    
    <link href="https://dor.ky/php-get-accurate-user-ip-address/" rel="alternate" type="text/html"/>
    
    <updated>2012-12-08T12:55:30-00:00</updated>
    <id>https://dor.ky/php-get-accurate-user-ip-address/</id>
    <content type="html">&lt;pre class=&quot;lang:php decode:true crayon-selected&quot; title=&quot;PHP: Get Accurate User IP Address&quot;&gt;// PHP: Get Accurate User IP Address  
function strFindCorrectIP() {  
    $headers = array(
        &#39;HTTP_CLIENT_IP&#39;,
        &#39;HTTP_X_FORWARDED_FOR&#39;,
        &#39;HTTP_X_FORWARDED&#39;,
        &#39;HTTP_X_CLUSTER_CLIENT_IP&#39;,
        &#39;HTTP_FORWARDED_FOR&#39;,
        &#39;HTTP_FORWARDED&#39;,
        &#39;REMOTE_ADDR&#39;
    );

    foreach ($headers as $key) {
        if (array_key_exists($key, $_SERVER) &amp;lt;mark&gt;= true) {
            foreach (explode(&#39;,&#39;, $_SERVER[$key]) as $ip) {
                if (filter_var($ip, FILTER_VALIDATE_IP) !&amp;lt;/mark&gt; false) {
                    return $ip;
                }
            }
        }
    }
}&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Taking Advice</title>
    
    <link href="https://dor.ky/taking-advice/" rel="alternate" type="text/html"/>
    
    <updated>2012-12-04T21:04:04-00:00</updated>
    <id>https://dor.ky/taking-advice/</id>
    <content type="html">&lt;p&gt;Over the years I’ve written numerous blog posts both on my own site and around the web too. They have ranged from topics close to home and choices in life that I’ve made, to being focused on programming and technology. I’ve often used my blog to share code snippets and to ask opinion on programming methods. As a person, I’m always keen to listen to others, both in technology and life.&lt;/p&gt;
&lt;p&gt;It’s always fascinating to learn how different people approach problems and whether I can learn anything from their methodologies (the answer to that is yes, I’ve learned a lot from others including correcting some of my own practices). I have always believed that you should take on board advice from others, especially those who have worked in the field for as long as you. There are far too many people who are ignorant to the methods of others, which cannot only cause stagnation in projects but also severe repercussions.&lt;/p&gt;
&lt;p&gt;Consider the following scenario:&lt;/p&gt;
&lt;p&gt;You have a project that has a login system or some form that someone else has written. After investigating further, you find a bug in this system that allows anyone to bypass the login mechanism. You report this to the developer of the application who then is adamant that they have correctly built the mechanism to their previous standards.&lt;/p&gt;
&lt;p&gt;The above scenario is entirely plausible, XSS, CORS and other hijacks are evolving all the time, a piece of code that you wrote two years ago could easily be insecure now. In our field and world of technology, we can never sit still. Things evolve constantly on the web and if you don’t change with the times then you’re going to have issues. I’ve spoken to a few people in the past who had the same attitude as mentioned above, their code was ‘secure’ when they wrote it so why should they have to change it now? It’s an all too common attitude within the programming world. A world where the majority of developers feel the need to 1-up each other and prove that they’re the best of the best. I can remember reading a blog post on a similar topic recently, ‘Developer Envy’. This attitude cannot only lead to problems when working in teams but also can be the downfall of major projects if it isn’t managed properly. Every one wants to succeed, that’s part of human nature.&lt;/p&gt;
&lt;p&gt;As a developer you have the right to question others and the way in which they have approached problems. When we were kids, we were always the ones who took their toys apart to see how the worked. This undying curiosity is what powers my life and my personality, I always want to know why. The same comes with the projects that I work on, if you have done something better then I’m happy to listen.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Google APIs Error &amp; Access Not Configured</title>
    
    <link href="https://dor.ky/google-apis-error-access-not-configured/" rel="alternate" type="text/html"/>
    
    <updated>2012-08-11T19:59:22-00:00</updated>
    <id>https://dor.ky/google-apis-error-access-not-configured/</id>
    <content type="html">&lt;p&gt;If you’re working with the Google APIs, one of the error messages you may come across as:&lt;/p&gt;
&lt;pre class=&quot;brush: actionscript3; gutter: true; first-line: 1&quot;&gt;403: Access Not Configured&lt;/pre&gt;
&lt;p&gt;All this simply means is that you haven’t set the service to ‘on’ in the APIs console and accepted the terms and conditions. Once you’ve done that then you request will function as expected.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Enable Emoji on iOS Devices</title>
    
    <link href="https://dor.ky/how-to-enable-emoji-on-ios-devices/" rel="alternate" type="text/html"/>
    
    <updated>2012-07-11T22:50:54-00:00</updated>
    <id>https://dor.ky/how-to-enable-emoji-on-ios-devices/</id>
    <content type="html">&lt;div&gt;
  &lt;div style=&quot;float: left;&quot;&gt;
    Step 1.&lt;br&gt;&lt;img title=&quot;IMG_0469E&quot; src=&quot;https://dor.ky/assets/images/old_content/IMG_0469E.png&quot; alt=&quot;&quot;&gt;
  &lt;/div&gt;
  &lt;div style=&quot;float: right;&quot;&gt;
    Step 2.&lt;br&gt;&lt;img title=&quot;IMG_0469E&quot; src=&quot;https://dor.ky/assets/images/old_content/IMG_0470E.png&quot; alt=&quot;&quot;&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
  &lt;div style=&quot;float: left;&quot;&gt;
    Step 3.&lt;br&gt;&lt;img title=&quot;IMG_0469E&quot; src=&quot;https://dor.ky/assets/images/old_content/IMG_0471E.png&quot; alt=&quot;&quot;&gt;
  &lt;/div&gt;
  &lt;div style=&quot;float: right;&quot;&gt;
    Step 4.&lt;br&gt;&lt;img title=&quot;IMG_0469E&quot; src=&quot;https://dor.ky/assets/images/old_content/IMG_0472E.png&quot; alt=&quot;&quot;&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
  &lt;div style=&quot;float: left;&quot;&gt;
    Step 5.&lt;br&gt;&lt;img title=&quot;IMG_0469E&quot; src=&quot;https://dor.ky/assets/images/old_content/IMG_0473E.png&quot; alt=&quot;&quot;&gt;
  &lt;/div&gt;
  &lt;div style=&quot;float: right;&quot;&gt;
    Step 6.&lt;br&gt;&lt;img title=&quot;IMG_0469E&quot; src=&quot;https://dor.ky/assets/images/old_content/IMG_0474E.png&quot; alt=&quot;&quot;&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
  &lt;div style=&quot;float: left;&quot;&gt;
    Step 7.&lt;br&gt;&lt;img title=&quot;IMG_0469E&quot; src=&quot;https://dor.ky/assets/images/old_content/IMG_0475E.png&quot; alt=&quot;&quot;&gt;
  &lt;/div&gt;
  &lt;div style=&quot;float: right;&quot;&gt;
    Step 8.&lt;br&gt;&lt;img title=&quot;IMG_0469E&quot; src=&quot;https://dor.ky/assets/images/old_content/IMG_0476E.png&quot; alt=&quot;&quot;&gt;
  &lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  
  
  <entry>
    <title>The Future of Debugging</title>
    
    <link href="https://dor.ky/the-future-of-debugging/" rel="alternate" type="text/html"/>
    
    <updated>2012-07-11T22:40:59-00:00</updated>
    <id>https://dor.ky/the-future-of-debugging/</id>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://twitter.com/Grumpydev/statuses/219803687810371584&quot;&gt;@Grumpydev&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>3D Views of the London Underground Stations</title>
    
    <link href="https://dor.ky/3d-views-of-the-london-underground-stations/" rel="alternate" type="text/html"/>
    
    <updated>2012-06-26T21:19:09-00:00</updated>
    <id>https://dor.ky/3d-views-of-the-london-underground-stations/</id>
    <content type="html">&lt;p&gt;It’s not very often that I come across a site which I find truly amazing. I came across &lt;a href=&quot;http://stations.aeracode.org/&quot;&gt;Station Maps&lt;/a&gt; by &lt;a href=&quot;http://www.aeracode.org/about/&quot;&gt;Andrew Godwin&lt;/a&gt; this evening and found them completely fascinating. I have a long standing interest in the London Underground system and to see the stations in this way rekindled that greatly.&lt;/p&gt;
&lt;p&gt;It’s truly amazing how complex &lt;a href=&quot;http://stations.aeracode.org/#bnk&quot;&gt;Bank&lt;/a&gt; and &lt;a href=&quot;http://stations.aeracode.org/#kxx&quot;&gt;King’s Cross St. Pancras&lt;/a&gt; are.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Oyster Card Travel History Now Online</title>
    
    <link href="https://dor.ky/oyster-card-travel-history-now-online/" rel="alternate" type="text/html"/>
    
    <updated>2012-06-07T02:07:50-00:00</updated>
    <id>https://dor.ky/oyster-card-travel-history-now-online/</id>
    <content type="html">&lt;p&gt;I’ve just had the following email from TFL explaining that they’ve now placed all my Oyster travel journeys into the online portal. Can’t wait to see if they expose this data via the API too.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I am writing to let you know we now offer an enhanced service for checking your journey history online.&lt;/p&gt;
&lt;p&gt;You will need an Oyster online account to access the service. If you do not have an account, you can create one by visiting &lt;a href=&quot;http://www.tfl.gov.uk/oyster&quot;&gt;tfl.gov.uk/oyster&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You will be able to see all your journeys made from the date you open your account, whether you use pay as you go, season ticket, Travelcard or a Bus &amp;amp; Tram Pass.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>PHP is Mostly CRUD</title>
    
    <link href="https://dor.ky/php-is-mostly-crud/" rel="alternate" type="text/html"/>
    
    <updated>2012-05-18T21:58:32-00:00</updated>
    <id>https://dor.ky/php-is-mostly-crud/</id>
    <content type="html">&lt;p&gt;I recently got the book “MongoDB and PHP” by Steve Francia which had an interesting paragraph in the first chapter that talks about how the use of stored data has changed in recent years:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With all the problems with ORMs, you may wonder why programmers use them at all. People were willing to make the compromises to adopt ORMs for one big reason; PHP applications are by and large CRUD applications. Rarely do they use all of the rich features the relational database provides, so giving them up seemed a small price to pay for the benefit of simplified access to the data. Additionally, there weren’t really any other good options. For very simple projects, one could write SQL in one’s code, but this was hard to debug and even harder to ensure that it was done securely. PHP is famous for enabling SQL injection attacks, as inexperienced developers pass variables right into the SQL without sanitization.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which lead me to think about how my own use of data has changed over the years.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Virtualmin, ProFTPd &amp;#038; Passive FTP</title>
    
    <link href="https://dor.ky/virtualmin-proftpd-passive-ftp/" rel="alternate" type="text/html"/>
    
    <updated>2012-05-13T11:26:09-00:00</updated>
    <id>https://dor.ky/virtualmin-proftpd-passive-ftp/</id>
    <content type="html">&lt;p&gt;The current version of Virtualmin ships with an issue for ProFTPd on CentOS due to two modules that it needs to track connections not being loaded. There is a quick fix for this, you’ll need to edit the iptables-config file located at:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; gutter: true; first-line: 1&quot;&gt;[root@pluto ~]# nano /etc/sysconfig/iptables-config&lt;/pre&gt;
&lt;p&gt;Add the end of the configuration file, add the following line:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; gutter: true; first-line: 1&quot;&gt;IPTABLES_MODULES=&quot;ip_conntrack_netbios_ns ip_conntrack_ftp&quot;&lt;/pre&gt;
&lt;p&gt;You can now restart the iptables service with the following command and FTP should work through passive mode:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; gutter: true; first-line: 1&quot;&gt;[root@pluto ~]# service iptables restart&lt;/pre&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Forcing SSL Protocol Using PHP or Apache&#39;s mod_rewrite</title>
    
    <link href="https://dor.ky/forcing-ssl-protocol-using-php-or-apaches-mod_rewrite/" rel="alternate" type="text/html"/>
    
    <updated>2012-05-11T20:30:35-00:00</updated>
    <id>https://dor.ky/forcing-ssl-protocol-using-php-or-apaches-mod_rewrite/</id>
    <content type="html">&lt;p&gt;There are quite a few circumstances where you may need to force a site, app or page to serve over a secure SSL connection. In PHP development there are two ways to approach this problem depending on your setup. If you’re using Apache to serve your site and you have the ability to use .htaccess files then you can use a rewrite rule to simplify this task server side.&lt;/p&gt;
&lt;h3 id=&quot;using-apache-mod_rewrite-to-force-ssl&quot;&gt;Using Apache mod_rewrite to force SSL&lt;/h3&gt;
&lt;p&gt;If you can use the mod_rewrite function below to enforce this server side.&lt;/p&gt;
&lt;h3 id=&quot;use-php-to-force-page-to-serve-over-ssl&quot;&gt;Use PHP to force page to serve over SSL&lt;/h3&gt;
&lt;p&gt;You may be in the position where you only need to redirect a certain page (although you could easily modify the rewrite rule above to do that) or you don’t have the ability to use .htaccess files then you will need to handle this within your actual PHP script.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Toronto Food &amp;#038; Place Reviews</title>
    
    <link href="https://dor.ky/toronto-food-place-reviews/" rel="alternate" type="text/html"/>
    
    <updated>2012-05-09T17:17:05-00:00</updated>
    <id>https://dor.ky/toronto-food-place-reviews/</id>
    <content type="html">&lt;p&gt;As you probably know, I was in Toronto for a couple of weeks earlier this year. In a new respectful habit I’m trying to force myself into I’m making my views on locations visited know via Foursquare and Google Places. The list below contains all the name worthy places I’d visited and a short review of each venue.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/toronto-pearson-international-airport-yyz/4acbafc4f964a520fbc420e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?cid=5797728056486936438&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;toronto-pearson-international-airport&quot;&gt;Toronto Pearson International Airport&lt;/h2&gt;
&lt;p&gt;Having been to Pearson a few times, I can safely say that it’s becoming a fairly known path for me. There is a large number of places to eat, drink and shop throughout the concourses. All of the airport staff are helpful and willing to assist you with anything you need. There are plenty of facilities around and always within reach of the gates. Enjoy every experience I’ve had with this airport and I’m sure most others do too.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/crowne-plaza-fallsview/4b79dbc4f964a52086162fe3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Crowne+Plaza+Hotel+Niagara+Falls+-+Fallsview,+Falls+Avenue,+Niagara+Falls,+ON,+Canada&amp;hl=en&amp;cid=1214648062937861821&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;crowne-plaza-fallsview&quot;&gt;Crowne Plaza Fallsview&lt;/h2&gt;
&lt;p&gt;While visiting Niagara Falls I stayed at the Crowne Plaza Fallsview hotel. The hotel isn’t similar to others in the area and it retains the old aura of a time gone by. The entrance hall, hallways and fittings all reflect the level of service that is provided by the staff. I spent two nights in Niagara Falls and both were pleasant. The bedrooms were clean, tidy and stocked full of helpful items. The service was great and there is a Starbucks at street level. The location is great to wander around Niagara Falls too, with the Maid of the Mist tours just a few minutes walk across the road.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/niagara-falls-canadian-side/4c26c7b2c11dc9b6a1ac2924&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=horseshoe,+Niagara+Falls,+Niagara+Falls,+ON,+Canada&amp;hl=en&amp;cid=3749916976460129124&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;niagara-falls&quot;&gt;Niagara Falls&lt;/h2&gt;
&lt;p&gt;For a very long time, Horseshoe Falls has been on the list of places I’ve wanted to visit in the world. While in Canada this time around I had the chance to actually go and stay in Niagara Falls and see the majestic Falls in all their glory. Along with doing the usual tourist things like Maid of the Mist (see below) it was also good to visit Clifton Hill which is very similar to Blackpool and the old English seafront arcades. The entire tourist area is a delight to walk around in with plenty of places to eat, buy and wander around. I was so awestruck by the sheer size and power of the Falls that I would recommend that every person in the world should go see.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/air-canada-centre/4b155081f964a520b4b023e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Air+Canada+Centre++40+Bay+St.,+Toronto,+ON+M5J+2X2&amp;hl=en&amp;cid=6359875317936854032&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;air-canada-centre&quot;&gt;Air Canada Centre&lt;/h2&gt;
&lt;p&gt;I was fortunate enough to see the Red Hot Chilli Peppers play live at the Air Canada Centre whilst I was in Toronto. The venue is in a great location downtown and easy enough to get to by subway, streetcar and by walking. The ACC staff are  extremely friendly and I had the pleasant experience of having ‘Lou’ as our usher for the night. Before the event started Lou spoke to myself and others seated nearby about his experience working at the ACC, he had missed two events in 30 years of working there which is an incredible!&lt;/p&gt;
&lt;p&gt;The facilities were great, clean and easy to locate. The merchandise for the concert was easy to find too!&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/maid-of-the-mist--canada-entry/4bb9f0a1935e952104852790&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content//BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Queen+Victoria+Park+at+Maid+of+the+Mist+Plaza,+Niagara+Falls,+ON+L2G+3K9&amp;hl=en&amp;cid=4619646691915021133&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;maid-of-the-mist&quot;&gt;Maid of the Mist&lt;/h2&gt;
&lt;p&gt;Along with seeing Niagara Falls, one of the other things I wanted to do was to take a trip on the world famous ‘Maid of the Mist’. Be careful if you want to go and visit this fantastic attraction and head over to the dock early in the morning. The queues build up extremely quickly and you can end up queuing for hours. The whole process was a pain free experience though, although it’s very wet when you’re in front of both the American and Horseshoe falls.&lt;/p&gt;
&lt;p&gt;The trip itself takes around 15 minutes after leaving the dock. If you can get onto the boat quickly then do so, as you’ll want to find yourself a good vantage point. Staff were most friendly and even offered to take photos for me too!&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/crescent-beach/4c3a009718e72d7ff0191bf5&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=+Crescent+Beach,+Fort+Erie,+ON+L2A&amp;hl=en&amp;ftid=0x89d31430e97ca591:0xfca47bcd0089a474&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;crescent-beach&quot;&gt;Crescent Beach&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/old-fort-erie/4c55be7206901b8d6168014e&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Old+Fort+Erie,+ON,+Canada&amp;hl=en&amp;ftid=0x89d31385103dd1ff:0x30fbe3053bea25eb&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;old-fort-erie&quot;&gt;Old Fort Erie&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/courtyard-by-marriott/4aa728fdf964a5200a4c20e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Courtyard+by+Marriott++475+Yonge+St.+(at+Wood+St.),+Toronto,+ON+M4Y+2W5&amp;hl=en&amp;cid=9657492142293288790&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;courtyard-by-marriott&quot;&gt;Courtyard by Marriott&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/coach-house-restaurant/4b2d27b4f964a520a6cf24e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Coach+House+Restaurant++574+Yonge+St.+(Wellesley),+Toronto,+Canada&amp;hl=en&amp;cid=3508147699244578037&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;coach-house-restaurant&quot;&gt;Coach House Restaurant&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/teds-collision/4ae0ff2ff964a520688421e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Ted%27s+Collision++573+College,+Toronto,+Canada&amp;hl=en&amp;cid=14337926159346661561&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;teds-collision&quot;&gt;Teds Collision&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/steam-whistle-brewing/4ad4c05ef964a520cbf620e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Steam+Whistle+Brewing++255+Bremner+Blvd.+(btwn+Rees+St.+%26+Simcoe+St.),+Toronto,+ON+M5V+3M9&amp;hl=en&amp;cid=8413786325743958701&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;steam-whistle-brewing&quot;&gt;Steam Whistle Brewing&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/cn-tower/4ad4c05ef964a52096f620e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=CN+Tower++301+Front+St.+W+(at+John+St.),+Toronto,+Ontario+M5V+2T6&amp;hl=en&amp;cid=1580157384328508801&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;cn-tower&quot;&gt;CN Tower&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/elephant--castle/4aa7b236f964a520fc4c20e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Elephant+%26+Castle++378+Yonge+Street+(at+Gerrard+St.+E),+Toronto,+ON+M5B1S6&amp;hl=en&amp;cid=9431400438203476604&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;elephant-%26-castle&quot;&gt;Elephant &amp;amp; Castle&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/the-county-general/4e7dfa0fe5e871fe304ad004&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=the-county-general,+toronto&amp;hl=en&amp;cid=15802776810215256988&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;the-county-general&quot;&gt;The County General&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/aw/4caf97981463a14346c995a9&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=A%26W++496+Yonge+St.+(at+Alexander+St.),+Toronto,+ON+M4Y+1X9&amp;hl=en&amp;cid=16041016777895286269&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;a%26w&quot;&gt;A&amp;amp;W&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/frans/4ae1296df964a5208c8521e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Fran%27s++20+College+St.+(at+Yonge+St.),+Toronto,+ON+M5G+1K2&amp;hl=en&amp;cid=7036570544090730430&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;frans&quot;&gt;Frans&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/pizza-pizza/4bc7c6eb8b7c9c74ac3337cf&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;#&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;pizza-pizza&quot;&gt;Pizza Pizza&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/teriyaki-express/4bd8bb2a2e6f0f4786550808&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;teriyaki-express&quot;&gt;Teriyaki Express&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/urban-eatery/4e5f92182271a996808eb626&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;urban-eatery&quot;&gt;Urban Eatery&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/starbucks/4ac6117ff964a520bfb220e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Starbucks++250+Queen+St+W+(at+John+St),+Toronto,+ON+M5V+2E3&amp;hl=en&amp;cid=1964490552018347849&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;starbucks&quot;&gt;Starbucks&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/bmo-field/4ad4c062f964a520f3f720e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=BMO+Field++170+Princes+Blvd.+(at+Lakeshore+%26+Strachan),+Toronto,+ON+M6K+3C3&amp;hl=en&amp;cid=16184036452841994637&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;bmo-field&quot;&gt;BMO Field&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/tim-hortons/4b843f5ef964a5202b2a31e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Tim+Hortons++444+Yonge+St+(at+College+St),+Toronto,+ON+M5B+2H4&amp;hl=en&amp;cid=16564042480635305228&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;tim-hortons&quot;&gt;Tim Hortons&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/sears/4af27d27f964a520c7e721e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Sears++290+Yonge+St+(Eaton+Centre),+Toronto,+ON+M5B+1C8&amp;hl=en&amp;cid=9466079484135977859&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;sears&quot;&gt;Sears&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/yongedundas-square/4ad8cd16f964a520c91421e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=Yonge-Dundas+Square,+Toronto,+ON+M5B+2R8&amp;hl=en&amp;cid=18132027203059742858&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;yonge-%26-dundas-square&quot;&gt;Yonge &amp;amp; Dundas Square&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/amc/4adbbae6f964a520402a21e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?q=AMC+Yonge+%26+Dundas+24,+10+Dundas+Street+East,+toronto&amp;hl=en&amp;ftid=0x882b34cad13905ff:0xa88f68e37c363b12&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;amc-cinema&quot;&gt;AMC Cinema&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
&lt;div class=&quot;separator&quot;&gt;
  &lt;a class=&quot;to_top&quot; href=&quot;#&quot;&gt; &lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;float: right; height: 24px; padding-top: 4px;&quot;&gt;
  &lt;a href=&quot;https://foursquare.com/v/the-pickle-barrel/4b3000d7f964a5203cf424e3&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View Venue on Foursquare&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_113.png&quot; alt=&quot;Foursquare&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://maps.google.co.uk/maps/place?cid=16372063297215739935&quot;&gt;&lt;img class=&quot;icon tooltip-s&quot; title=&quot;View on Google Places&quot; src=&quot;https://dor.ky/assets/images/old_content/BSN_106.png&quot; alt=&quot;Google Places&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;the-pickle-barrel&quot;&gt;The Pickle Barrel&lt;/h2&gt;
&lt;p&gt;Review content.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Kuala Lumpur Makes Internet Access a Requirement for Food and Drink Outlets</title>
    
    <link href="https://dor.ky/kuala-lumpur-makes-internet-access-a-requirement-for-food-and-drink-outlets/" rel="alternate" type="text/html"/>
    
    <updated>2012-01-21T23:14:16-00:00</updated>
    <id>https://dor.ky/kuala-lumpur-makes-internet-access-a-requirement-for-food-and-drink-outlets/</id>
    <content type="html">&lt;p&gt;A lot of things get my attention in the news now-a-days but a piece from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kuala_Lumpur&quot; target=&quot;_blank&quot;&gt;Kuala Lumpur&lt;/a&gt; impressed me. A new law has been passed in Kuala Lumpur that stipulates food and drink outlets must now provide free wireless internet in order to be granted or to renew a license to operate. I think this is a fantastic step from the local government as Internet access has been a must have for most people in recent years.&lt;/p&gt;
&lt;p&gt;Here in the UK, we’re often lucky that most popular coffee houses such as &lt;a href=&quot;http://www.starbucks.com/&quot; target=&quot;_blank&quot;&gt;Starbucks&lt;/a&gt; or &lt;a href=&quot;http://www.costacoffee.co.uk/&quot; target=&quot;_blank&quot;&gt;Costa Coffee&lt;/a&gt; and food outlets such as &lt;a href=&quot;http://www.mcdonalds.co.uk/&quot; target=&quot;_blank&quot;&gt;McDonalds&lt;/a&gt; have long provided free WiFi. Starbucks do it in a very interesting way and effectively allow members of their reward scheme to have free Internet access whereas non-members have to use &lt;a href=&quot;http://www.btopenzone.com/&quot; target=&quot;_blank&quot;&gt;BT OpenZone&lt;/a&gt;. Registration is free, so there is no reason for you not to sign up and its a valuable marketing tool for Starbucks.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Get Week Start and End Timestamps in PHP</title>
    
    <link href="https://dor.ky/get-week-start-and-end-timestamps-in-php/" rel="alternate" type="text/html"/>
    
    <updated>2012-01-15T20:15:58-00:00</updated>
    <id>https://dor.ky/get-week-start-and-end-timestamps-in-php/</id>
    <content type="html">&lt;p&gt;For a recent piece of PHP I was writing I needed to find the start and end timestamps for a given week. I came up with the following piece of code to achieve getting the timestamps.&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/ssx/2687628.js&quot;&gt;&lt;/script&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Facebook Feature Request - Event Search to Honour &#39;center&#39; and &#39;distance&#39; Parameters</title>
    
    <link href="https://dor.ky/facebook-feature-request-event-search-to-honour-center-and-distance-parameters/" rel="alternate" type="text/html"/>
    
    <updated>2012-01-07T17:59:03-00:00</updated>
    <id>https://dor.ky/facebook-feature-request-event-search-to-honour-center-and-distance-parameters/</id>
    <content type="html">&lt;p&gt;For quite a while now one feature I’ve felt was missing from the &lt;a href=&quot;http://developers.facebook.com/docs/reference/api/&quot; target=&quot;_blank&quot;&gt;Facebook Graph API&lt;/a&gt; was searching for events by latitude and longitude along with a distance. You can currently issue a search for &lt;span class=&quot;monospaced&quot;&gt;place&lt;/span&gt; objects, but the &lt;span class=&quot;monospaced&quot;&gt;place&lt;/span&gt; object is the only one which honours the &lt;span class=&quot;monospaced&quot;&gt;center&lt;/span&gt; and &lt;span class=&quot;monospaced&quot;&gt;distance&lt;/span&gt; parameters.&lt;/p&gt;
&lt;p&gt;I’ve filed a bug report for the feature request for Facebook to implement this and we’ll see how that progresses. If you would like to add your notes to the feature request or show your support you can do so at &lt;a href=&quot;https://developers.facebook.com/bugs/288653361182652&quot; target=&quot;_blank&quot;&gt;https://developers.facebook.com/bugs/288653361182652&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Create a New Google Account Without Gmail</title>
    
    <link href="https://dor.ky/create-a-new-google-account-without-gmail/" rel="alternate" type="text/html"/>
    
    <updated>2012-01-05T20:06:30-00:00</updated>
    <id>https://dor.ky/create-a-new-google-account-without-gmail/</id>
    <content type="html">&lt;p&gt;A couple of times recently I’ve needed to create new Google accounts. If you’ve recently needed to do this you probably noticed that Google’s default form now wants you to effectively create a ‘screen name’ which will come with GMail.&lt;/p&gt;
&lt;p&gt;I’d imagine this is a ploy to push more users to Google+ and its a smart way to do it, however if you want to use your existing email address then you will need to use the old formatted signup page which you can find at &lt;a href=&quot;https://accounts.google.com/SignUpWithoutGmail&quot; target=&quot;_blank&quot;&gt;https://accounts.google.com/SignUpWithoutGmail&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>What is a Wharf?</title>
    
    <link href="https://dor.ky/what-is-a-wharf/" rel="alternate" type="text/html"/>
    
    <updated>2012-01-01T15:57:36-00:00</updated>
    <id>https://dor.ky/what-is-a-wharf/</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/content_old/butlers-wharf.jpg&quot; alt=&quot;Butlers Wharf, London&quot;&gt;&lt;/p&gt;
&lt;p&gt;When I went to visit &lt;a href=&quot;http://www.last.fm/&quot; target=&quot;_blank&quot;&gt;Last.fm&lt;/a&gt; in&lt;br&gt;
London last year I took some time to wander around the City as I do most times&lt;br&gt;
I’m in London. This particular time I decided to take one of the&lt;br&gt;
riverboats down to Greenwich – for a long time now, Greenwich has been&lt;br&gt;
one of my favourite places in and around London. While I was on the riverboat&lt;br&gt;
the tour guide was discussing local points of interest which they have done many&lt;br&gt;
times before. However, this time he pointed out a sign which said Wharf above a&lt;br&gt;
new apartment block. After then asking all of the people on the riverboat if they&lt;br&gt;
knew the meaning of the word wharf non did. Up to that point in my life even I&lt;br&gt;
hadn’t questioned what the meaning of it was.&lt;/p&gt;
&lt;p&gt;As it was explained to us, a wharf is a Ware House At River Front. During the&lt;br&gt;
late 1800s this were prevalent all along the Thames and most other waterside&lt;br&gt;
locations.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Creating and Requesting SSL Certificates</title>
    
    <link href="https://dor.ky/creating-and-requesting-ssl-certificates/" rel="alternate" type="text/html"/>
    
    <updated>2011-12-30T21:48:14-00:00</updated>
    <id>https://dor.ky/creating-and-requesting-ssl-certificates/</id>
    <content type="html">&lt;p&gt;One of the less common server tasks during the year is the setup and maintenance of SSL certificates for web services. There has always been the air of dread when this comes around but I’m not too sure where the reason for that comes from. The process is simple enough to go through and you have two choices in how you use SSL.&lt;/p&gt;
&lt;p&gt;You can either generate your own certificate which will cause the users browser to prompt (this is by design, you’re not a certificate authority) or you can purchase a certificate from an authority such as Verisign. Most of the larger certificate authorities are accepted by 99% of browsers. There are various levels of certificate validation which include domain validation (providing you own the domain), extended validation (proving you are a business/individual) and enterprise level validation.&lt;/p&gt;
&lt;p&gt;The first thing you will need to do is generate your own key if you haven’t done so already. Using the openssl program you can generate your own key using the following command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;openssl genrsa -des3 -out my.key 2048&amp;lt;br /&amp;gt;&lt;/code&gt;&lt;br&gt;
This will generate a private key for you using 2,048 bits of encryption. Some certificate authorities require this level of encryption.&lt;/p&gt;
&lt;p&gt;Now that you have your own identity key you can create a Certificate Signing Request (CSR). This is a request to an authority to create a certificate on your behalf. The program will ask you a series of questions that you need to answer. The most important of these is the FQDN field which must match the site you’re securing. Again, using OpenSSL you can use this command to generate your CSR:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;openssl req -new -key my.key -out my.csr&amp;lt;br /&amp;gt;&lt;/code&gt;&lt;br&gt;
If you want to generate your own self signed certificate then you can use the following OpenSSL command to do so. This generates a certificate that is valid for 365 days from today:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;openssl x509 -req -days 365 -in my.csr -signkey my.key -out my.crt&amp;lt;br /&amp;gt;&lt;/code&gt;&lt;br&gt;
If for any reason you would like to remove the passphrase/password from your private key, you can do so using the command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;openssl rsa -in www.key -out new.key&lt;/code&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Enable Keyboard Repeat in OSX Lion</title>
    
    <link href="https://dor.ky/enable-keyboard-repeat-in-osx-lion/" rel="alternate" type="text/html"/>
    
    <updated>2011-12-24T21:46:43-00:00</updated>
    <id>https://dor.ky/enable-keyboard-repeat-in-osx-lion/</id>
    <content type="html">&lt;p&gt;An odd bug in OSX Lion means that the keyboard repeat rate options in the Keyboard preference pane doesn’t get honoured. To enable this, you can run the following command at a Terminal prompt:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;defaults write -g ApplePressAndHoldEnabled -bool false&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Then either logout or restart your machine to force a re-read of the defaults configuration.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Set Your Facebook Username</title>
    
    <link href="https://dor.ky/set-your-facebook-username/" rel="alternate" type="text/html"/>
    
    <updated>2011-12-18T22:11:40-00:00</updated>
    <id>https://dor.ky/set-your-facebook-username/</id>
    <content type="html">&lt;p&gt;One of the most often asked questions for me when it comes to Facebook is how administrators of pages and profiles can set usernames. In the past, Facebook haven’t really pushed this feature but in the age where social marketing and name based branding is becoming more important – setting your username is a bonus point when it comes to promoting your brand.&lt;/p&gt;
&lt;p&gt;You can set your Facebook username at the following URL:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;a href=&amp;quot;http://www.facebook.com/username/&amp;quot; target=&amp;quot;_new&amp;quot;&amp;gt;http://www.facebook.com/username/&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Changing Running Styles to Help Your Knee</title>
    
    <link href="https://dor.ky/changing-running-styles-to-help-your-knee/" rel="alternate" type="text/html"/>
    
    <updated>2011-12-18T22:08:43-00:00</updated>
    <id>https://dor.ky/changing-running-styles-to-help-your-knee/</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=7jrnj-7YKZE&quot;&gt;http://www.youtube.com/watch?v=7jrnj-7YKZE&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;http://www.youtube.com/watch?v=XrOgDCZ4GUo&amp;amp;feature=related&quot;&gt;http://www.youtube.com/watch?v=XrOgDCZ4GUo&amp;amp;feature=related&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Enable Airdrop for All Macs</title>
    
    <link href="https://dor.ky/enable-airdrop-for-all-macs/" rel="alternate" type="text/html"/>
    
    <updated>2011-11-13T17:01:58-00:00</updated>
    <id>https://dor.ky/enable-airdrop-for-all-macs/</id>
    <content type="html">&lt;p&gt;Fire up a terminal and enter the following to enable Airdrop on all macs:&lt;/p&gt;
&lt;p&gt;defaults write com.apple.NetworkBrowser BrowseAllInterfaces 1&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Using the Skype Protocol Handler</title>
    
    <link href="https://dor.ky/using-the-skype-protocol-handler/" rel="alternate" type="text/html"/>
    
    <updated>2011-10-19T19:23:52-00:00</updated>
    <id>https://dor.ky/using-the-skype-protocol-handler/</id>
    <content type="html">&lt;p&gt;A lot of people use Skype now-a-days and one convenient feature is the ability to use the skype:// protocol handler for creating actionable links on the web. Examples of this are to initiate a call, or add a user as a friend. The list below details the types of links that you can use:&lt;/p&gt;
&lt;table style=&quot;width: 680px&quot; border=&quot;0&quot;&gt;
  &lt;tr&gt;
    &lt;td&gt;
      Action
    &lt;/td&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;td&amp;gt;
  Example Link
&amp;lt;/td&amp;gt;

&amp;lt;td&amp;gt;
  Result
&amp;lt;/td&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/tr&gt;
  &lt;tr class=&quot;table-odd&quot;&gt;
    &lt;td&gt;
      Call User
    &lt;/td&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;td&amp;gt;
  &amp;lt;a href=&amp;quot;dordotky?call&amp;quot;&amp;gt;skype:dordotky?call&amp;lt;/a&amp;gt;
&amp;lt;/td&amp;gt;

&amp;lt;td&amp;gt;
  Skype will initiate a call to the user
&amp;lt;/td&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/tr&gt;
  &lt;tr class=&quot;table-even&quot;&gt;
    &lt;td&gt;
      Add User
    &lt;/td&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;td&amp;gt;
  &amp;lt;a href=&amp;quot;dordotky?add&amp;quot;&amp;gt;skype:dordotky?add&amp;lt;/a&amp;gt;
&amp;lt;/td&amp;gt;

&amp;lt;td&amp;gt;
  Skype will pop up a box to add the user
&amp;lt;/td&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/tr&gt;
  &lt;tr class=&quot;table-odd&quot;&gt;
    &lt;td&gt;
      Chat with User
    &lt;/td&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;td&amp;gt;
  &amp;lt;a href=&amp;quot;dordotky?chat&amp;quot;&amp;gt;skype:dordotky?chat&amp;lt;/a&amp;gt;
&amp;lt;/td&amp;gt;

&amp;lt;td&amp;gt;
  Skype will initiate a chat with the user
&amp;lt;/td&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/tr&gt;
  &lt;tr class=&quot;table-even&quot;&gt;
    &lt;td&gt;
      View Profile
    &lt;/td&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;td&amp;gt;
  &amp;lt;a href=&amp;quot;dordotky?userinfo&amp;quot;&amp;gt;skype:dordotky?userinfo&amp;lt;/a&amp;gt;
&amp;lt;/td&amp;gt;

&amp;lt;td&amp;gt;
  Skype will open the &amp;amp;#8216;View Profile&#39; window for the given user
&amp;lt;/td&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/tr&gt;
  &lt;tr class=&quot;table-odd&quot;&gt;
    &lt;td&gt;
      Leave Voicemail
    &lt;/td&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;td&amp;gt;
  &amp;lt;a href=&amp;quot;dordotky?voicemail&amp;quot;&amp;gt;skype:dordotky?voicemail&amp;lt;/a&amp;gt;
&amp;lt;/td&amp;gt;

&amp;lt;td&amp;gt;
  Skype will record a voicemail to leave for user
&amp;lt;/td&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/tr&gt;
  &lt;tr class=&quot;table-even&quot;&gt;
    &lt;td&gt;
      Send File
    &lt;/td&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;td&amp;gt;
  &amp;lt;a href=&amp;quot;dordotky?sendfile&amp;quot;&amp;gt;skype:dordotky?sendfile&amp;lt;/a&amp;gt;
&amp;lt;/td&amp;gt;

&amp;lt;td&amp;gt;
  Skype will initiate a file send to a user
&amp;lt;/td&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/tr&gt;
&lt;/table&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Check Your Apple Product Warranty Online</title>
    
    <link href="https://dor.ky/check-your-apple-product-warranty-online/" rel="alternate" type="text/html"/>
    
    <updated>2011-10-01T20:50:13-00:00</updated>
    <id>https://dor.ky/check-your-apple-product-warranty-online/</id>
    <content type="html">&lt;p&gt;If you would like to check the status of your Apple products, enter the serial number below and click ‘Check Warranty’. If you need help finding your serial, take a look at &lt;a href=&quot;http://support.apple.com/kb/HT1349&quot;&gt;Apple’s official instructions&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Report IP or Copyright Infringements on Facebook</title>
    
    <link href="https://dor.ky/how-to-report-ip-or-copyright-infringements-on-facebook/" rel="alternate" type="text/html"/>
    
    <updated>2011-10-01T18:45:44-00:00</updated>
    <id>https://dor.ky/how-to-report-ip-or-copyright-infringements-on-facebook/</id>
    <content type="html">&lt;p&gt;One task I had to recently complete was cleaning up the Facebook ecosystem for a particular business. Around Facebook there were a few groups, profiles and pages purporting to be the business which needed removing. There are two types of infringement that you can report to Facebook and get actioned, explained below.&lt;/p&gt;
&lt;h4&gt;Copyrighted Works&lt;/h4&gt;
&lt;p&gt;For copyrighted works, such as music, movies or images you can have them removed via the &lt;a href=&quot;http://www.facebook.com/legal/copyright.php?copyright_notice=1&quot;&gt;Facebook automated DCMA removal form&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Intellectual Property&lt;/h4&gt;
&lt;p&gt;If you are the legitimate representative of a business you can ask Facebook to remove any unofficial pages, groups or profiles which are purporting to be you. You need to complete the &lt;a href=&quot;http://www.facebook.com/legal/copyright.php?noncopyright_notice=1&quot;&gt;Facebook non-copyright removal form&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title></title>
    
    <link href="https://dor.ky/posts/2011/09/what-is-a-qr-code/" rel="alternate" type="text/html"/>
    
    <updated>2011-09-17T00:00:00-00:00</updated>
    <id>https://dor.ky/posts/2011/09/what-is-a-qr-code/</id>
    <content type="html">&lt;p&gt;commercial—&lt;br&gt;
id: 38&lt;br&gt;
title: What is a QR Code?&lt;br&gt;
date: 2011-09-17T15:37:15+00:00&lt;/p&gt;
&lt;p&gt;guid: &lt;a href=&quot;http://beta.dor.ky/2011/09/17/what-is-a-qr-code/&quot;&gt;http://beta.dor.ky/2011/09/17/what-is-a-qr-code/&lt;/a&gt;&lt;br&gt;
permalink: /what-is-a-qr-code/&lt;/p&gt;
&lt;hr&gt;
&lt;img class=&quot;float-right&quot; style=&quot;margin: 15px 0px 10px 10px&quot; src=&quot;https://dor.ky/assets/images/old_content/7480257909040b9a475661d46700db75.jpg&quot; alt=&quot;&quot;&gt;
&lt;p&gt;This is a post that I’ve constructed using a number of sources (linked at the bottom of this post) and from my own use of QR codes.&lt;/p&gt;
&lt;h4&gt;Purpose&lt;/h4&gt;
&lt;p&gt;A QR code (abbreviated from Quick Response code) is a type of matrix barcode (or two-dimensional code) first designed for the automotive industry. More recently, the system has become popular outside of industry due to its fast readability and comparatively large storage capacity. The code consists of black modules arranged in a square pattern on a white background. The information encoded can be made up of any kind of data (e.g. binary, alphanumeric, or Kanji symbols).&lt;/p&gt;
&lt;p&gt;QR codes storing addresses and Uniform Resource Locators (URLs) may appear in magazines, on signs, on buses, on business cards, or on almost any object about which users might need information. Users with a camera phone equipped with the correct reader application can scan the image of the QR code to display text, contact information, connect to a wireless network, or open a web page in the telephone’s browser. This act of linking from physical world objects is termed hard-linking or object hyperlinking.&lt;/p&gt;
&lt;p&gt;QR codes can be used in Google’s mobile Android operating system via both their own Google Goggles application or 3rd party barcode scanners like ZXing or Kaywa. The browser supports URI redirection, which allows QR codes to send metadata to existing applications on the device. Nokia’s Symbian operating system features a barcode scanner which can read QR codes, while mbarcode is a QR code reader for the Maemo operating system. In the Apple iOS, a QR code reader is not natively included, but more than fifty paid and free apps are available with both scanning capabilities and hard-linking to URI available. With BlackBerry devices, the App World application can natively scan QR codes and load any recognised Web URLs on the device’s Web browser. Following an upcoming update, Windows Phone 7 will be able to scan QR codes through the Bing search app.&lt;/p&gt;
&lt;!--SNIP--&gt;
&lt;h4&gt;History&lt;/h4&gt;
&lt;p&gt;Created by Toyota subsidiary Denso Wave in 1994, the QR code is one of the most popular types of two-dimensional barcodes. The QR code was designed to allow its contents to be decoded at high speed.&lt;/p&gt;
&lt;p&gt;Although initially used for tracking parts in vehicle manufacturing, QR codes as of 2011 are used in a much broader context. Uses extend from commercial tracking to entertainment and from product marketing to in-store product labelling. Many of these applications target toward mobile-phone users (via mobile tagging). Users may receive text, add a vCard contact to their device, open a Uniform Resource Identifier (URI), or compose an e-mail or text message after scanning QR codes. They can generate and print their own QR codes for others to scan and use by visiting one of several paid and free QR code generating sites or apps. Google has a popular API to generate QR codes, and Apps for scanning QR codes can be found on nearly all smartphone devices.&lt;/p&gt;
&lt;p&gt;There are several standards in documents covering the physical encoding of QR codes:&lt;/p&gt;
&lt;ul style=&quot;margin-left: 20px&quot;&gt;
  &lt;li&gt;
    &lt;strong&gt;October 1997&lt;/strong&gt;&lt;br&gt;AIM (Association for Automatic Identification and Mobility) International &lt;p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;January 1999&lt;/strong&gt;&lt;br&gt;JIS X 0510 &lt;p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;June 2000&lt;/strong&gt;&lt;br&gt; ISO/IEC 18004:2000 Information technology&lt;br&gt; Automatic identification and data capture techniques&lt;br&gt; Bar code symbology&lt;br&gt; QR code (now withdrawn)&lt;br&gt;Defines QR code models 1 and 2 symbols. &lt;p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;September 1, 2006&lt;/strong&gt;&lt;br&gt; ISO/IEC 18004:2006 Information technology&lt;br&gt; Automatic identification and data capture techniques&lt;br&gt; QR code 2005 bar code symbology specification&lt;br&gt; Defines QR code 2005 symbols, an extension of QR code model 2. Does not specify how to read QR code model 1 symbols, or require this for compliance.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the application layer, there is some variation between implementations. NTT DoCoMo has established de facto standards for the encoding of URLs, contact information, and several other data types. The open-source “ZXing” project maintains a list of QR code data types which are discussed in the ‘Embedded Media into QR Codes’ section of this post.&lt;/p&gt;
&lt;h4&gt;Adoption&lt;/h4&gt;
&lt;p&gt;The technology has seen frequent use in Japan and South Korea; the United Kingdom is the seventh-largest national consumer of QR codes. In the US, QR Code usage is expanding. During the month of June 2011, according to one study, 14 million mobile users scanned a QR Code or a barcode. 58% of those users scanned a QR or bar code from their home, while 39% scanned from retail stores. 60% of the 14 million users were men between the age of 18-34.&lt;/p&gt;
&lt;p&gt;While the adoption of QR codes in some markets has been slow to begin (particularly in markets such as the United States where competing standards such as Data Matrix exist), the technology is gaining some traction in the smartphone market. Many Android, Nokia, Blackberry handsets, and the Nintendo 3DS, come with QR code readers installed. QR reader software is available for most mobile platforms. Moreover there are number of online QR code generators where users can create QR codes for their own needs.&lt;/p&gt;
&lt;h4&gt;Embedded Media into QR Codes&lt;/h4&gt;
&lt;p&gt;The actual idea of embedded media into a QR is a bit of a myth. QR codes can only store alphanumeric characters and a selection of symbols. You can invoke different types of actions by using URL/protocol schemes which are defined by each QR reader. The following list details the types of URL schemes that you can use.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a class=&quot;float-right ml15&quot; title=&quot;QR Code&quot; href=&quot;https://dor.ky/assets/images/old_content/qr_contact_fu.png&quot; rel=&quot;prettyPhoto[qr_images]&quot;&gt;&lt;img class=&quot;pretty-box&quot; src=&quot;https://dor.ky/assets/images/old_content/qr_contact_fu.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;strong&gt;Contact Information&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;QR codes can contain contact information so someone can easily scan a QR code, view your contact details, and add you on their phone. You can input your name, phone number, e-mail, address, website, memo, and more. I&#39;ve commonly seen these used on business cards, for instance. You give someone a business card, they see a QR code on the back, scan it with their phone, and easily add your contact info to their phone.
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;a class=&quot;float-right ml15&quot; title=&quot;QR Code&quot; href=&quot;https://dor.ky/assets/images/old_content/qr_cal_fu.png&quot; rel=&quot;prettyPhoto[qr_images]&quot;&gt;&lt;img class=&quot;pretty-box&quot; src=&quot;https://dor.ky/assets/images/old_content/qr_cal_fu.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;strong&gt;Calendar Event&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;If you have an event you want to promote, you can create a QR code containing info for that event. QR codes containing event info can contain event title, start and end date/time, time zone, location, and description. This could work well on an event flyer or possibly even on a website promoting.
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;a class=&quot;float-right ml15&quot; title=&quot;QR Code&quot; href=&quot;https://dor.ky/assets/images/old_content/qr_contact_fu.png&quot; rel=&quot;prettyPhoto[qr_images]&quot;&gt;&lt;img class=&quot;pretty-box&quot; src=&quot;https://dor.ky/assets/images/old_content/qr_contact_fu.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;strong&gt;E-mail Address&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;Nice and simply, eh? A QR code can contain your e-mail address so someone can scan the code, see your e-mail, and then open an e-mail on their phones. If your call to action is mostly to have someone e-mail you, this would be great.
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;a class=&quot;float-right ml15&quot; title=&quot;QR Code&quot; href=&quot;https://dor.ky/assets/images/old_content/qr_phone_fu.png&quot; rel=&quot;prettyPhoto[qr_images]&quot;&gt;&lt;img class=&quot;pretty-box&quot; src=&quot;https://dor.ky/assets/images/old_content/qr_phone_fu.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;strong&gt;Phone Number&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;Maybe e-mail isn&#39;t immediate enough and you want someone to call. Link them up to a phone number.
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;&lt;a class=&quot;float-right ml15&quot; title=&quot;QR Code&quot; href=&quot;https://dor.ky/assets/images/old_content/qr_geolocation_fu.png&quot; rel=&quot;prettyPhoto[qr_images]&quot;&gt;&lt;img class=&quot;pretty-box&quot; src=&quot;https://dor.ky/assets/images/old_content/qr_geolocation_fu.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;strong&gt;Geolocation&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;If you have an event you want to promote, you might want to stick a QR code linking someone to a Google Maps location. This will allow someone to scan your QR code and get directions so they don&#39;t have to manually type in an address. Although some may prefer to type it in, it doesn&#39;t hurt to give them another option.
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;&lt;a class=&quot;float-right ml15&quot; title=&quot;QR Code&quot; href=&quot;https://dor.ky/assets/images/old_content/qr_sms_fu.png&quot; rel=&quot;prettyPhoto[qr_images]&quot;&gt;&lt;img class=&quot;pretty-box&quot; src=&quot;https://dor.ky/assets/images/old_content/qr_sms_fu.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;strong&gt;SMS&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;QR codes can populate a text message with a number and message. You can have your QR code send you a text saying, &amp;amp;#8220;Tell me more about XYZ&amp;amp;#8221; for instance. This is great when paired with text message marketing.
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;&lt;a class=&quot;float-right ml15&quot; title=&quot;QR Code&quot; href=&quot;https://dor.ky/assets/images/old_content/qr_text_fu.png&quot; rel=&quot;prettyPhoto[qr_images]&quot;&gt;&lt;img class=&quot;pretty-box&quot; src=&quot;https://dor.ky/assets/images/old_content/qr_text_fu.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;strong&gt;Text&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;You can also just have a sentence or a paragraph of text. This could be fun for having some type of QR code based game where you can leave hints in QR codes.
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;&lt;a class=&quot;float-right ml15&quot; title=&quot;QR Code&quot; href=&quot;https://dor.ky/assets/images/old_content/qr_wifi_fu.png&quot; rel=&quot;prettyPhoto[qr_images]&quot;&gt;&lt;img class=&quot;pretty-box&quot; src=&quot;https://dor.ky/assets/images/old_content/qr_wifi_fu.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;strong&gt;Wifi Network&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;Do you hate telling someone a long WEP wireless key that&#39;s a pain to type out on a mobile phone? Set it up so someone can scan a QR code and automatically configure wifi on their phones.
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;&lt;a class=&quot;float-right ml15&quot; title=&quot;QR Code&quot; href=&quot;https://dor.ky/assets/images/old_content/qr_url_fu.png&quot; rel=&quot;prettyPhoto[qr_images]&quot;&gt;&lt;img class=&quot;pretty-box&quot; src=&quot;https://dor.ky/assets/images/old_content/qr_url_fu.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;strong&gt;URL&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;Don&#39;t think little of this 3-letter data type. This is where the possibilities become endless. You can use a link that takes someone to your Facebook fan page or Twitter profile. You can also link someone to a YouTube video. Or maybe you want someone to pay for something via PayPal.
&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;clear-both&quot;&gt;
  Did I mention all of these services have mobile-friendly versions of their website? That is, if you link someone to your Twitter page they&#39;ll be redirected to a version that&#39;s built specifically for their smartphone? Don&#39;t forget to make sure the link goes to a website that&#39;s optimised for mobile devices.
&lt;/p&gt;
&lt;h4&gt;Licensing&lt;/h4&gt;
&lt;p&gt;The use of QR codes is free of any license. The QR code is clearly defined and published as an ISO standard. Denso Wave owns the patent rights on QR codes, but has chosen not to exercise them. In the US, the granted QR code patent is US5726435. In Japan it is JP2938338. In Germany it is DE69518098. (The European Patent Office granted patent EP0672994 to Denso Wave, but Denso only “nationalised” the patent grant in Germany.) The term QR code itself is a registered trademark of Denso Wave Incorporated.&lt;/p&gt;
&lt;h4&gt;Risks of using QR Codes&lt;/h4&gt;
&lt;p&gt;Malicious QR Codes combined with a permissive Reader can put a computer’s contents and user’s privacy at risk. QR Codes intentionally obscure and compress their contents and intent to humans. QR codes are easily created and may be affixed over legitimate QR Codes. On a smartphone, the Reader’s many permissions may allow use of the camera, full internet access, read/write contact data, GPS, read browser history, read/write local storage, and global system changes.&lt;/p&gt;
&lt;p&gt;Risks include linking to dangerous websites with browser exploits, enabling the microphone/camera/GPS and then streaming those feeds to a remote server, exfiltrating sensitive data (passwords, files, contacts, transactions), sending email/SMS/IM messages or DDOS packets as part of a botnet, corrupting your privacy settings, stealing your identity, and even containing malicious logic themselves such as JavaScript or a virus. These actions may occur in the background whereas the user only sees the Reader open a harmless webpage.&lt;/p&gt;
&lt;h4&gt;Commercial Uses&lt;/h4&gt;
&lt;p&gt;The use of commercial QR codes is increasingly greatly. The recent Red Hot Chilli Peppers album adverts for the album “I’m With You” had a creative QR code within the posters as &lt;a href=&quot;http://cooladsniceart.blogspot.com/2011/08/red-hot-chili-peppers-qr-code-campaign.html&quot; target=&quot;_blank&quot;&gt;Catalina Cadena notes in her blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Data capacity&lt;/h4&gt;
&lt;p&gt;The amount of data that can be stored in the QR code depends on the character set, version and error correction level.&lt;/p&gt;
&lt;h4&gt;Error Correction&lt;/h4&gt;
&lt;p&gt;Codewords are 8 bits long and use the Reed–Solomon error correction algorithm with four error correction levels. The higher the error correction level, the less storage capacity. At the highest error correction level it is possible to create artistic QR codes that still scan correctly, but contain intentional errors to make them more readable or attractive to the human eye, as well as to incorporate colours, logos and other features into the QR code block. While the exact number of errors that can be corrected depends on the size of the symbol and the location of the errors, the following table lists the approximate error correction capability at each of the four levels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Level L — 7% of codewords can be restored&lt;/li&gt;
&lt;li&gt;Level M — 15% of codewords can be restored&lt;/li&gt;
&lt;li&gt;Level Q — 25% of codewords can be restored&lt;/li&gt;
&lt;li&gt;Level H — 30% of codewords can be restored&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Uses of QR&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Business Cards.&lt;br&gt;
Stick a QR code on the back of your business card and have it link to your phone number, send a text message, link to your website, or even take someone to a Youtube video.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Flyers.&lt;br&gt;
Handing out flyers door-to-door? Or maybe you want to spread the news about an event in a new and innovative way? Slap a QR code on it and link to an event page or a video describing more about the event. Check out how one clothing retailer is doing this. You can also add social media icons so people can share.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Billboards.&lt;br&gt;
This one way communication channel just became interactive. Calvin Klein used QR codes on billboards in New York and Los Angeles with their Uncensored campaign. It linked to a page with a mobile video and Twitter/Facebook share icons. Simple? You bet. Learn more about it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Comics.&lt;br&gt;
That’s right, QR codes have been used in comics. It was done with Donald Duck for kids!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Education.&lt;br&gt;
Use QR codes next to math problems in math books that pull up a video that teaches students how to complete certain problems. Let’s just hope they scan the QR code after they answered it! I picked up this idea on Youtube.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Articles in Magazines/Newspaper.&lt;br&gt;
Magazine publishers can use QR codes in articles that link to more info on the article, a video, or even a discussion board. Wait. Stop. Think about that. Another one-way communication channel that is now engaging. Imagine someone reading an article, wanting to voice their opinion and leave a comment like they would on a website blog, scanning a QR code, and then leaving comments on an article they found in the paper medium. Talk about in-the-moment engagement. Simply fascinating.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For Sale Signs on Homes.&lt;br&gt;
Real Estate, anyone? Print a QR code on a for sale sign on a home that connects the mobile user to a mobile website that shows them more info on the home and includes a video with a walk-through of the home (which they wouldn’t otherwise be able to see). Or just link to a Youtube video. Talk about point-of-experience!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Comment Cards.&lt;br&gt;
Tired of paper comment cards? Want to reduce error and capture feedback at the point-of-experience? Or maybe there is a trust issue with the manager and you think he’s trashing some bad comment cards? Either way, mobile web-based comment cards allow for convenience and meet the consumer where there are. Comments can be e-mailed to someone and added to an excel file if need be. Theoretically, someone can file a complaint and a manager (as well as corporate, if needed) can receive the complaint via e-mail and respond to it before the customer has even left the building. Talk about real-time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Presentations.&lt;br&gt;
More and more I’ve seen less of the traditional speaker presentations. Audiences want to engage during presentations and throw in their two cents, just like they do on Twitter. The unGEEKED e’lite conference is built on this idea. One way to engage the audience is to stick a QR code in a presentation. Maybe the audience can scan it and be put on a mailing list, ask a question, or give their input on the presentation at the end, all via the mobile web. This would work best at conferences where early adopters are present.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Clothing.&lt;br&gt;
Want to be different? How about you stick a QR code on a shirt. How’s that for standing out against the crowd? Or clothing companies can use QR codes on  tags to display colour, style, size, and more about that item.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Television.&lt;br&gt;
This is extremely fascinating. Again, a one way communication channel… is now interactive. QR codes on TV allows for viewers to answer quizzes, sign up for a mailing list, find a Facebook fan page, and more. Although executed poorly, FOX tried this.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Books.&lt;br&gt;
How about a QR code at the end of each chapter, which links to a discussion board where readers can share comments on a chapter. Amazing. Or maybe you want to describe a concept with digital media. Video, anyone? Or maybe the author wants to link you to a page with errata.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Outdoor Games.&lt;br&gt;
Ever participate in a scavenger hunt? With QR codes, you can leave digital tips for people. How about a video hint or video riddle?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Direct Mail.&lt;br&gt;
QR codes on direct mail allows for people to scan and learn more about a product or service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Instruction Manual.&lt;br&gt;
With some products, a paper manual isn’t enough. People need a video to help visualise how things go together. Or maybe you just want to give that personal feeling and talk about why it’s awesome.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Interactive Menus.&lt;br&gt;
In restaurants, consumers can scan QR codes in the menu and watch a video on how that dish was prepared, see the ingredients, learn more about the executive chef with an interview, or even the staff. Stop. Think about that personal connection for a minute. Think about the story that someone can go tell their friends. They came to order food, but their experience was heightened because they were also able to walk away with a recipe for their favorite dish (or something more). That is remarkable, as Seth Godin says. Again, the possibilities are endless. What’s important is the creative process and brainstorming.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cereal Box.&lt;br&gt;
Cereal boxes already have games on them, but how about games on a smartphone? Or maybe you want to have a “story of the day” or talk about what the brand is doing. This is a completely new way to engage with consumers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Products.&lt;br&gt;
QR codes can be used on products to connect real life to the digital world. Maybe you want to build awareness for a Facebook fan page or a Twitter account.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Facebook Like.&lt;br&gt;
A service called Likify allows someone to do exactly that: like your Facebook fan page. Learn more about them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Call/E-mail Us.&lt;br&gt;
Simple enough? Have a QR code that brings up your phone number so someone can easily scan and call you or send you an e-mail.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Coupons.&lt;br&gt;
Use a QR code to link to a special coupon that is shareable via social media. It can be tracked and turned off at any time. Goodbye paper coupons! (Did I mention this is environmentally friendly, too?)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Name Tags.&lt;br&gt;
Although the idea of someone coming up and scanning your name tag at a conference sounds kind of funny, it can definitely help differentiate you and be a great conversation starter. There is a standard for storing contact info on QR codes. Use quiQR to create your virtual contact card today so someone can easily add you as a contact on their phone.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Website Contact Us.&lt;br&gt;
If you already cater to your mobile audience, you can use QR codes on your contact us page. Maybe you want to link them to your mobile resource and remind them to bookmark it so they can use it on the go. Or maybe you want to make it so they can easily scan a QR code and call you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Conferences.&lt;br&gt;
Conferences can use QR codes for speaker feedback or conference feedback and evaluation. Attendees can share their thoughts via their mobile phone, and not a paper card with hard-to-read handwriting.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Event Tickets.&lt;br&gt;
On a printed ticket, QR codes can be used to link to a video introduction to the event, or maybe link to a free MP3 download for a band. This is also good for tracking tickets, which Eventbrite does.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Window Displays.&lt;br&gt;
Use QR codes on windows displays to give those window shoppers one more thing to look at (and talk about!). It can link to a video with someone talking about the product (very personal), or maybe you want to highlight certain features about the product.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Classified Ads.&lt;br&gt;
Selling a car? Hiring someone? Link to a personal video on Youtube which has you expanding on the opportunity or telling people why it’s a good one.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Variants of QR Codes&lt;/h4&gt;
&lt;p&gt;Micro QR code is a smaller version of the QR code standard for applications with less ability to handle large scans. There are different forms of Micro QR codes as well. The highest of these can hold 35 numeric characters. Standard QR code is the QR code standard for applications that possess the ability to handle large scans. A standard QR code can contain up to 7089 characters, though not all QR readers can accept that much data.&lt;/p&gt;
&lt;p&gt;Although encrypted QR codes are not very common, there are a few implementations. An Android app, for example, manages encryption and decryption of QR codes using a secure AES 128 algorithm. A special form of secure quick response codes utilising public key encryption are SKS codes which have identical appearance to normal QR codes. SKS codes were designed for one-time-use and are created by encrypting a precursor hardware security token such as the CID written in the ROM of a microSD card, applying a time stamp and displaying the code on for example the high resolution screen of a mobile handset. SKS codes are closely analogous to One-time pad which are highly secure and can therefore be used for applications demanding high security such as mobile financial transactions. SKS codes in fact combine the CID and GMT with other proprietary data related to the transaction, an assembly of datum which never occurs again and which is discarded after being decrypted and processed on the transaction server. SKS codes were first developed in 2010 by Japanese company Yodo KK and are patent pending.&lt;/p&gt;
&lt;h4&gt;Links/Credits&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.denso-wave.com/qrcode/aboutqr-e.html&quot; target=&quot;_blank&quot;&gt;http://www.denso-wave.com/qrcode/aboutqr-e.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://notixtech.com/blog/9-qr-code-data-types&quot; target=&quot;_blank&quot;&gt;http://notixtech.com/blog/9-qr-code-data-types&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Expose Email Addresses via Twitter API</title>
    
    <link href="https://dor.ky/expose-email-addresses-via-twitter-api/" rel="alternate" type="text/html"/>
    
    <updated>2011-09-10T16:39:14-00:00</updated>
    <id>https://dor.ky/expose-email-addresses-via-twitter-api/</id>
    <content type="html">&lt;p&gt;One of the most popular posts that I wrote previously for my blog was regarding the Twitter API and email addresses. That post has since been permanently archived and is no longer available It seems as though this topic is very popular among new developers to the Twitter ecosystem. In this post, I’m going to revisit that topic once again.&lt;/p&gt;
&lt;h6&gt;How do I get the email address of a user using the Twitter API?&lt;/h6&gt;
&lt;p&gt;This is a very simple question to answer. You can’t.&lt;/p&gt;
&lt;h6&gt;Why are email addresses not available via the Twitter API?&lt;/h6&gt;
&lt;p&gt;There is not a single reason why Twitter should hand over the email addresses of its users to anyone. Any application that you develop should explicitly ask the user the input their email address, clearly stating why you believe you need it.&lt;/p&gt;
&lt;p&gt;User addresses are private, just like telephone numbers. The only need for email addresses to be exposed via the API is for spam harvesting which is a big no-no.&lt;/p&gt;
&lt;h6&gt;I want to keep my application users informed about changes&lt;/h6&gt;
&lt;p&gt;This is a reasonable thought, but consider the viewpoint of your users. The will follow the account associated with your application for news and updates. Users will also expect to find news, updates and important content via your application.&lt;/p&gt;
&lt;h6&gt;Will Twitter ever open up the API to disclose email addresses?&lt;/h6&gt;
&lt;p&gt;No, and that’s a good thing.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Fixing a Rattling Garmin eTrex Vista HCx</title>
    
    <link href="https://dor.ky/fixing-a-rattling-garmin-etrex-vista-hcx/" rel="alternate" type="text/html"/>
    
    <updated>2010-12-31T12:27:48-00:00</updated>
    <id>https://dor.ky/fixing-a-rattling-garmin-etrex-vista-hcx/</id>
    <content type="html">&lt;p&gt;The eTrex Vista HCx is a fantastic little GPSr. The one that I currently have is from Matthew who loaned it earlier this year when our Dakota malfunctioned. After being out in the Roaches, the eTrex suffered an impact injury and began to rattle. Fortunately this was easy to fix as it was only a cover of the speaker inside the GPSr.&lt;/p&gt;
&lt;img src=&quot;https://dor.ky/assets/images/old_content/IMG_0007.jpg&quot; alt=&quot;IMG_0007.jpg&quot; class=&quot;border-dark&quot;&gt;
&lt;p&gt;To begin, remove the batteries and battery cover. Now remove the black rubber casing band around the GPSr. When you’ve removed this completely you will see some clear plastic tape of which there are three layers. Remove each clear tape label in turn and then carefully keep them to the side as you’ll need them afterwards. You will then have your GPSr open as shown in the photo below. Unclip the top from the bottom gently as this will make reattaching the broken piece easier.&lt;/p&gt;
&lt;img alt=&quot;/assets/images/old_content/IMG_0006.jpg&quot; src=&quot;https://dor.ky/fixing-a-rattling-garmin-etrex-vista-hcx/IMG_0006.jpg&quot; class=&quot;border-dark&quot;&gt;
&lt;p&gt;You can now see the piece that has broken off (if you’ve broken the same piece as me that is). If you’re lucky you will be able to clip it back into place. Failing that then reattach it and super-glue into place but be sure of leave two sides open so the speak still works correctly. The image below shows the speaker without its case attached.&lt;/p&gt;
&lt;img src=&quot;https://dor.ky/assets/images/old_content/IMG_0008.jpg&quot; alt=&quot;IMG_0008.jpg&quot; class=&quot;border-dark&quot;&gt;
&lt;p&gt;Carefully put your eTrex back together and it’ll be as good as new. You can also use these instructions for opening your eTrex for anything else you may need to.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to Install OpenStreetMap Maps onto a Garmin GPSr</title>
    
    <link href="https://dor.ky/how-to-install-openstreetmap-maps-onto-a-garmin-gpsr/" rel="alternate" type="text/html"/>
    
    <updated>2010-11-12T22:41:50-00:00</updated>
    <id>https://dor.ky/how-to-install-openstreetmap-maps-onto-a-garmin-gpsr/</id>
    <content type="html">&lt;p&gt;Garmin provide many types of maps for their devices but each costs quite a large sum of money. Thankfully in recent months this process has become a lot easier for the end user to do. This short guide will explain where to find the correct map file and how to install it using a Dakota 10 GPSr, a Mac and Garmin&amp;quot;s free software.&lt;/p&gt;
&lt;h3 id=&quot;openstreetmap&quot;&gt;OpenStreetMap&lt;/h3&gt;
&lt;p&gt;The OpenStreetMap project provides map data for a large amount of the world for free. Even though the project is community edited – its still an excellent free map to use on your portable GPSr device. If you take a look at the list of maps available on the OSM site (&lt;a href=&quot;http://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/Download#Europe&quot;&gt;located here for the UK&lt;/a&gt;) you will see how many different people are providing packages/data files that can be used with Garmin devices.&lt;/p&gt;
&lt;h3 id=&quot;find-your-new-map&quot;&gt;Find Your New Map&lt;/h3&gt;
&lt;p&gt;The choice I made for UK maps with contours and routing is the maps created by user &lt;a href=&quot;http://talkytoaster.info/ukmaps.htm&quot;&gt;“Talkytoaster”&lt;/a&gt; and can be found at his website. At the present time the latest file is “101105” and the filename is &lt;a href=&quot;http://talkytoaster.info/ukmaps.htm&quot;&gt;“101105-UK+Contours-Routable.gmapi.zip”&lt;/a&gt; which will be a file compatible with Garmin&amp;quot;s MapInstall software on the Mac.&lt;/p&gt;
&lt;h3 id=&quot;install-using-garmin-mapinstall&quot;&gt;Install using Garmin MapInstall&lt;/h3&gt;
&lt;p&gt;Once you have got your file downloaded (which is probably a few hundred MB) then unzip the file you downloaded. You can plug in your GPSr and run the Garmin MapInstall software on your Mac. Follow the process on-screen and after a short time it’ll be done. Reboot your GPSr and you’ll notice that while its loading at boot time you’ll have a piece of text that says “OPENSTREETMAP”.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Why GeoCaching.com Needs an API</title>
    
    <link href="https://dor.ky/why-geocachingcom-needs-an-api/" rel="alternate" type="text/html"/>
    
    <updated>2010-10-15T21:25:26-00:00</updated>
    <id>https://dor.ky/why-geocachingcom-needs-an-api/</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/content_old/cc4fce1dac35a2f614483fbc78bfeb41.jpg&quot; alt=&quot;An all too common sight with the iPhone Application&quot; style=&quot;float: right; margin-left: 15px; margin-bottom: 5px; margin-top: 6px&quot;&gt;A lot of what I talk about these days seems to be Geocaching related. The concept of Geocaching has long been around and at present the biggest central location of cache information is at &lt;a href=&quot;http://www.geocaching.com/&quot;&gt;geocaching.com&lt;/a&gt; which is owned by &lt;a href=&quot;http://www.groundspeak.com/&quot;&gt;Groundspeak&lt;/a&gt;. The website, applications and tools are pretty average to use and no real changes have been made to the way that users interact with the site for a long time. The iPhone application is clunky at best and is a difficult to use at times. The reliability of the application over mobile connections is also questionable. All of the caching data is held by Groundspeak and although premium members can retrieve data via Pocket Queries (multiple caches in a single &lt;a href=&quot;http://www.topografix.com/gpx.asp&quot;&gt;GPX&lt;/a&gt;/&lt;a href=&quot;http://www.vterrain.org/Implementation/Formats/loc.html&quot;&gt;LOC&lt;/a&gt; file) and single file downloads (one cache per &lt;a href=&quot;http://www.topografix.com/gpx.asp&quot;&gt;GPX&lt;/a&gt;/&lt;a href=&quot;http://www.vterrain.org/Implementation/Formats/loc.html&quot;&gt;LOC&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;There is no public API for developers or users to use. There is no systematic way other than scraping to fetch cache data – and this is against the terms of the site and services. There are many good reasons why Groundspeak should introduce a public developer API. It makes no difference if it is licensed and paid for, developers will still use it and it would boost the bottom line for Groundspeak.&lt;/p&gt;
&lt;h3 id=&quot;uses-of-an-api&quot;&gt;Uses of an API&lt;/h3&gt;
&lt;p&gt;By opening up the data to developers, better applications can be created and users get choice. Choice is a very good thing. You only need to look at the enormous amount of Twitter applications that have made the ecosystem flourish and people can decide to use an application that provides them with the features that they want and less of what they don’t want.&lt;/p&gt;
&lt;h3 id=&quot;pushing-innovation&quot;&gt;Pushing Innovation&lt;/h3&gt;
&lt;p&gt;This fuelling of innovation can only help Groundspeak increase its revenues and expand Geocaching to a bigger audience. The more people that are using the API, site and products can only enhance what Groundspeak have to offer. Using the example of Twitter clients again, products that have implemented good ideas and functions often get copied: as the famous quotation goes “imitation is the highest form of flattery”. The problem with this is that at the present time Groundspeak are merely stagnating Geocaching for developers and in turn the end user.&lt;/p&gt;
&lt;h3 id=&quot;implementation&quot;&gt;Implementation&lt;/h3&gt;
&lt;p&gt;Any public facing API needs to be controlled in access and usage. This is to prevent aggressive over use and people not abiding by the terms of use. Leaning towards Facebook and Twitter’s APIs who both have very good usage policies and methods of dealing with over use by rate limiting, you can see effective throughput can be efficiently handled and scaled.&lt;/p&gt;
&lt;h3 id=&quot;free-use-or-premium&quot;&gt;Free Use or Premium&lt;/h3&gt;
&lt;p&gt;The other side of providing the API is the cost of covering running the service. Access to it could be funded by providing to premium users only. If access if provided to premium users only, even without an increase in price the bottom line for Groundspeak would improve and a lot more users would pump money into the ecosystem by purchasing third party applications that would require premium memberships.&lt;/p&gt;
&lt;h3 id=&quot;gce%3Astandard&quot;&gt;GCE:Standard&lt;/h3&gt;
&lt;p&gt;Any implementation of an API would likely provide either &lt;a href=&quot;http://en.wikipedia.org/wiki/XML&quot;&gt;XML&lt;/a&gt; or &lt;a href=&quot;http://json.org/&quot;&gt;JSON&lt;/a&gt;. An extension of this could be a new multi purpose format for cache information exchange, perhaps a new GeoCacheExchange:standard.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>T-Mobile Customers Can Now Use Orange Too</title>
    
    <link href="https://dor.ky/t-mobile-customers-can-now-use-orange-too/" rel="alternate" type="text/html"/>
    
    <updated>2010-10-12T17:19:07-00:00</updated>
    <id>https://dor.ky/t-mobile-customers-can-now-use-orange-too/</id>
    <content type="html">&lt;p&gt;Earlier this year T-Mobile announced that they were merging with Orange. This didn’t matter too much to most at the time but its changed a little now. For a while they’ve been testing network sharing and its now live for customers to use. If you’re on T-Mobile you need to first text ‘Yes’ to 2121. This will switch your account to use both networks and whichever has a signal. You’ll get a text back saying that your account has been changed. Remember that at present if you’re a T-Mobile customer using the Orange network you only get 2G, not 3G so things like YouTube won’t work (unless you’re jailbroken and forcing it to).&lt;/p&gt;
&lt;p&gt;I’ve tested it myself and it works flawlessly. If you’re an iPhone user you will need to make a few change to your settings. Goto Settings.app, click ‘General’ then ‘Network’ and turn on Data Roaming. If you want to force your phone into using Orange, click ‘Carrier’ and change to Orange (or T-Mobile Orange if its called that for you).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dor.ky/assets/images/old_content/114deace6fe679f29fe32786493a0e48.jpg&quot; rel=&quot;prettyPhoto&quot;&gt;&lt;img class=&quot;border-dark&quot; style=&quot;width: 200px; float: left; margin-right: 10px;&quot; src=&quot;https://dor.ky/assets/images/old_content/114deace6fe679f29fe32786493a0e48.jpg&quot; alt=&quot; &quot;&gt;&lt;/a&gt; &lt;a href=&quot;https://dor.ky/assets/images/old_content/77e58c97a8b45bd743a2e63c2ddbe3eb.jpg&quot; rel=&quot;prettyPhoto&quot;&gt;&lt;img class=&quot;border-dark&quot; style=&quot;width: 200px; float: left;&quot; src=&quot;https://dor.ky/assets/images/old_content/77e58c97a8b45bd743a2e63c2ddbe3eb.jpg&quot; alt=&quot; &quot;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Twitter API and Email Addresses</title>
    
    <link href="https://dor.ky/twitter-api-and-email-address/" rel="alternate" type="text/html"/>
    
    <updated>2010-10-02T22:17:00-00:00</updated>
    <id>https://dor.ky/twitter-api-and-email-address/</id>
    <content type="html">&lt;p&gt;One thing that appears to be a recurring theme on the Twitter API development mailing list and in the IRC channel of Freenode is the question of getting access to a users email address. I’ve always found this frustrating and have never seen a good reason why a users email address should be given out via any API method. The following list contains the reasons that are most often given when you ask why an email address is desired:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I’d Like to Contact the users of my application:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;See below.
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Auto-Notices &amp;amp; Spam:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;Not a chance.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It really is that simple. If you need a users email address then provide a settings page and ask them to enter it. Don’t think you can systematically fetch it from the API because you can’t, more to the point: I don’t think you’ll ever be able to.&lt;/p&gt;
&lt;p&gt;And that’s a good thing.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Open Data Results</title>
    
    <link href="https://dor.ky/open-data-results/" rel="alternate" type="text/html"/>
    
    <updated>2010-10-01T20:40:23-00:00</updated>
    <id>https://dor.ky/open-data-results/</id>
    <content type="html">&lt;p&gt;I was asked earlier this year to take part in an Open Data survey to see how data was being used. The survey was performed by Tim Davies. You can find the &lt;a href=&quot;http://practicalparticipation.co.uk/odi/report/&quot;&gt;report here&lt;/a&gt; or a &lt;a href=&quot;http://practicalparticipation.co.uk/odi/report/2010/research-summary/&quot;&gt;summary here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>A Guide to Geocaching</title>
    
    <link href="https://dor.ky/guide-to-geocaching/" rel="alternate" type="text/html"/>
    
    <updated>2010-09-06T10:13:18-00:00</updated>
    <id>https://dor.ky/guide-to-geocaching/</id>
    <content type="html">&lt;p&gt;As many of the regular readers of this site and my Twitter account will know, I’ve very much integrated GeoCaching into my daily life. Just like pringles you won’t be able to stop once you’ve started. GeoCaching is a very simple premise that is similar in principle to the old idea of letter-boxing. You can sign up at &lt;a href=&quot;http://www.geocaching.com/&quot;&gt;geocaching.com&lt;/a&gt; for an account an begin looking for GeoCaches in your area straight away. You will need some form of GPS receiver such as a Garmin. This article provides a little information on how to find a GeoCache and the best ways to hide your own caches.&lt;/p&gt;
&lt;div class=&quot;clearer&quot;&gt;
&lt;/div&gt;
&lt;h3 id=&quot;finding-a-geocache&quot;&gt;Finding a GeoCache&lt;/h3&gt;
&lt;p&gt;When attempting to find a GeoCache there is no particular set of rules that you need to adhere to. The following is a list of how I’d recommend you start looking for a GeoCache.&lt;/p&gt;
&lt;ol class=&quot;number-pad&quot;&gt;
  &lt;li&gt;
    Look for something out of place, or something placed deliberately as its extremely difficult to make a hide look natural.
  &lt;/li&gt;
  &lt;li&gt;
    Be aware of the container you&#39;re looking for, look for a gap or hole that the container could fit in.
  &lt;/li&gt;
  &lt;li&gt;
    Caches are often covered in leaves, rocks, sticks or a camouflage bag.
  &lt;/li&gt;
  &lt;li&gt;
    If you&#39;re new to GeoCaching, then read the hint provided, look at the photos posted and read recent logs of the cache to see what other people have said when looking around for it.
  &lt;/li&gt;
  &lt;li&gt;
    Have a little patience. Sometimes it can take a while to find a cache, even experienced GeoCaches will have times when they don&#39;t find a cache quickly.
  &lt;/li&gt;
  &lt;li&gt;
    Try to be discreet. You&#39;re often in public areas and no one wants caches to get trashed/muggled. At times, you will need to use stealth.
  &lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;clearer&quot;&gt;
&lt;/div&gt;
&lt;h3 id=&quot;how-to-hide-a-geocache&quot;&gt;How to Hide a GeoCache&lt;/h3&gt;
&lt;p&gt;After you’ve made your first finds you’ll have a better understanding of what makes a great GeoCache. I usually recommend that people consider hiding caches after they’ve made 50 or so finds as you have a better knowledge of the sport. The list below provides some tips on placing a GeoCache and things to avoid doing.&lt;/p&gt;
&lt;ol class=&quot;number-pad&quot;&gt;
  &lt;li&gt;
    Cross check your co-ordinates with other devices. iPhones and smart-phones do *not* provide good co-ordinates under any form of tree cover. If you have difficulty in getting co-ordinate accuracy, please note this in your cache listing. People won&#39;t mind, they just want to know the right areas to search and finders are happy to post their co-ordinates.
  &lt;/li&gt;
  &lt;li&gt;
    Make your cache hide as natural as possible. If you&#39;re using rocks at the base of a tree, or sticks in a rock formation then it will be too easy for the GeoCachers to find.
  &lt;/li&gt;
  &lt;li&gt;
    Holes make great hiding places.
  &lt;/li&gt;
  &lt;li&gt;
    If there is more than one way to approach your cache, make sure you&#39;ve hidden it from all approaches.
  &lt;/li&gt;
  &lt;li&gt;
    If you need to use a lot of camouflage then consider a different location.
  &lt;/li&gt;
  &lt;li&gt;
    If its on the bank of a waterway, use &amp;#8220;East Bank&amp;#8221; for descriptions and hints. Using &amp;#8220;Its on the other side&amp;#8221; is almost useless in these situations.
  &lt;/li&gt;
  &lt;li&gt;
    Try to get permission before placing your cache. Places like Peak District, National Park, Forestry Commission are all happy to give permission for caches. They just like to know where they are.
  &lt;/li&gt;
  &lt;li&gt;
    Try to place caches in areas of interest that people will enjoy seeing. Would you like to go here yourself?
  &lt;/li&gt;
  &lt;li&gt;
    Remember, people love a challenge. Be inventive.
  &lt;/li&gt;
  &lt;li&gt;
    Don&#39;t forget that you need to maintain a cache. If for some reason you can no longer maintain it, say so and usually someone is happy to adopt it.
  &lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;clearer&quot;&gt;
&lt;/div&gt;
&lt;h3 id=&quot;other-tips&quot;&gt;Other Tips&lt;/h3&gt;
&lt;ul class=&quot;bullet-check&quot;&gt;
  &lt;li&gt;
    Wear long trousers and take gloves as you&#39;ll most likely encounter nettles and hawthorns.
  &lt;/li&gt;
  &lt;li&gt;
    Always take a drink/bag of crisps with you, you&#39;ll nearly always be out for longer than you expect.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have any other tips or comments then please add them in the comment section for others to read.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Twitter API Oauth Update Status</title>
    
    <link href="https://dor.ky/twitter-api-oauth-update-status/" rel="alternate" type="text/html"/>
    
    <updated>2010-08-21T21:42:27-00:00</updated>
    <id>https://dor.ky/twitter-api-oauth-update-status/</id>
    <content type="html">&lt;p&gt;This PHP script will post an update to Twitter using OAuth. You can download the complete script and library &lt;a href=&quot;https://dor.ky/assets/images/old_content/oauth-php.zip&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;The Actual Script&lt;/h4&gt;
&lt;p&gt;1&lt;/p&gt;
&lt;div class=&quot;clear&quot;&gt;
  &amp;nbsp
&lt;/div&gt;
&lt;h4&gt;Running the Script&lt;/h4&gt;
&lt;p&gt;&lt;a class=&quot;img&quot; name=&quot;twitter-run&quot;&gt;&lt;/a&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/baef9202db4680c78a8cfbff3ffd71b4.jpg&quot; alt=&quot; &quot;&gt;&lt;/p&gt;
&lt;div class=&quot;clear&quot;&gt;
  &amp;nbsp
&lt;/div&gt;
&lt;h4&gt;The End Product&lt;/h4&gt;
&lt;p&gt;&lt;a class=&quot;img&quot; name=&quot;twitter-done&quot;&gt;&lt;/a&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/a18f0d49bf71701ad49d59d639d192d7.jpg&quot; alt=&quot; &quot;&gt;&lt;/p&gt;
&lt;div class=&quot;clear&quot;&gt;
  &amp;nbsp
&lt;/div&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Check Apple Device Warranty</title>
    
    <link href="https://dor.ky/check-apple-device-warranty/" rel="alternate" type="text/html"/>
    
    <updated>2010-08-17T11:49:36-00:00</updated>
    <id>https://dor.ky/check-apple-device-warranty/</id>
    <content type="html">&lt;p&gt;You can get quick information about any of your Apple devices by using their self service warranty information page, &lt;a href=&quot;https://selfsolve.apple.com/GetWarranty.do&quot;&gt;located here&lt;/a&gt;. For serial numbers from iPhones and iPads it’ll show supported networks, current warranty status and a little more. Its also useful for checking legitimacy of serial numbers.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Parsing GeoCache GPX with PHP</title>
    
    <link href="https://dor.ky/parsing-geocache-gpx-with-php/" rel="alternate" type="text/html"/>
    
    <updated>2010-08-13T16:10:16-00:00</updated>
    <id>https://dor.ky/parsing-geocache-gpx-with-php/</id>
    <content type="html">&lt;p&gt;While working on the new cache pages for this site I came across the interesting task of parsing GPX files with PHP. SimpleXML is quite easy to use and with the children() function you can use namespace extensions – for example with GeoCaching exported GPX files. You can get an awful lot more information from a GeoCache GPX than with standard XML parsing.&lt;/p&gt;
&lt;p&gt;The following is an example of a GPX file from the Geocaching site:&lt;/p&gt;
&lt;p&gt;Now, as you can see there is a large amount of data contained within this file. Using PHP and SimpleXML you can extract this data quite easily, by doing something similar to this:&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Local Businesses Should Harness Locality Services</title>
    
    <link href="https://dor.ky/local-businesses-should-harness-locality-services/" rel="alternate" type="text/html"/>
    
    <updated>2010-05-07T16:52:41-00:00</updated>
    <id>https://dor.ky/local-businesses-should-harness-locality-services/</id>
    <content type="html">&lt;p&gt;There is an emerging trend that local business won’t be able to ignore for too long. At the moment, all the rage with mobile devices seems to be location based services and games with &lt;a href=&quot;http://www.gowalla.com/&quot;&gt;Gowalla&lt;/a&gt;, &lt;a href=&quot;http://www.foursquare.com/&quot;&gt;FourSquare&lt;/a&gt; and &lt;a href=&quot;http://www.yelp.com/&quot;&gt;Yelp&lt;/a&gt; being the primary platforms although Facebook is to launch its own version shortly which may comprise of an amalgamation of all three. These platforms reward users with points, prizes and badges the more they ‘check in’. I haven’t had chance to test out Yelp more yet, so I’ll exclude that from the results below.&lt;/p&gt;
&lt;p&gt;There are a few subtle differences between the two platforms, which I’ll detail below. I’ve found that most people seem to use both Gowalla and FourSquare. At the moment, I’m leaning more towards being a Gowalla permanent user. I’ll outline a few differences with the platforms below.&lt;/p&gt;
&lt;table id=&quot;FeatureMatrix&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;
      Feature / Terminology
    &lt;/th&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;th class=&amp;quot;matrixColumn&amp;quot;&amp;gt;
  &amp;lt;h5&amp;gt;
    Foursquare
  &amp;lt;/h5&amp;gt;
  
  &amp;lt;p&amp;gt;
    &amp;lt;img src=&amp;quot;/media/icon/other/foursquare.png&amp;quot; alt=&amp;quot; &amp;quot; /&amp;gt;&amp;lt;/th&amp;gt; 
    
    &amp;lt;th class=&amp;quot;matrixColumn&amp;quot;&amp;gt;
      &amp;lt;h5&amp;gt;
        Gowalla
      &amp;lt;/h5&amp;gt;
      
      &amp;lt;p&amp;gt;
        &amp;lt;img src=&amp;quot;/media/icon/other/gowalla.png&amp;quot; alt=&amp;quot; &amp;quot; /&amp;gt;&amp;lt;/th&amp;gt; 
        
        &amp;lt;th class=&amp;quot;matrixColumn&amp;quot;&amp;gt;
          &amp;lt;h5&amp;gt;
            Brightkite
          &amp;lt;/h5&amp;gt;
          
          &amp;lt;p&amp;gt;
            &amp;lt;img src=&amp;quot;/media/icon/other/brightkite.png&amp;quot; alt=&amp;quot; &amp;quot; /&amp;gt;&amp;lt;/th&amp;gt; &amp;lt;/tr&amp;gt; 
            
            &amp;lt;tr&amp;gt;
              &amp;lt;td class=&amp;quot;matrixItem&amp;quot;&amp;gt;
                Marking as Present
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd&amp;quot;&amp;gt;
                Check In
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixEven&amp;quot;&amp;gt;
                Check In
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd&amp;quot;&amp;gt;
                Check In
              &amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
            
            &amp;lt;tr&amp;gt;
              &amp;lt;td class=&amp;quot;matrixItem&amp;quot;&amp;gt;
                Most Frequent Visitor
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd&amp;quot;&amp;gt;
                Mayor
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixEven&amp;quot;&amp;gt;
                Leader
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd&amp;quot;&amp;gt;
                TBC
              &amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
            
            &amp;lt;tr&amp;gt;
              &amp;lt;td class=&amp;quot;matrixItem&amp;quot;&amp;gt;
                Media Uploads
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd checkNone&amp;quot;&amp;gt;
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixEven checkMark&amp;quot;&amp;gt;
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd checkMark&amp;quot;&amp;gt;
              &amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
            
            &amp;lt;tr&amp;gt;
              &amp;lt;td class=&amp;quot;matrixItem&amp;quot;&amp;gt;
                API
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd checkMark&amp;quot;&amp;gt;
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixEven checkMark&amp;quot;&amp;gt;
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd checkMark&amp;quot;&amp;gt;
              &amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
            
            &amp;lt;tr&amp;gt;
              &amp;lt;td class=&amp;quot;matrixItem&amp;quot;&amp;gt;
                Userbase
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd&amp;quot;&amp;gt;
                TBC
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixEven&amp;quot;&amp;gt;
                TBC
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd&amp;quot;&amp;gt;
                TBC
              &amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
            
            &amp;lt;tr&amp;gt;
              &amp;lt;td class=&amp;quot;matrixItem last&amp;quot;&amp;gt;
                Push Notices
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd checkNone last&amp;quot;&amp;gt;
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixEven checkMark last&amp;quot;&amp;gt;
              &amp;lt;/td&amp;gt;
              
              &amp;lt;td class=&amp;quot;matrixOdd last&amp;quot;&amp;gt;
                TBC
              &amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;&amp;lt;/tbody&amp;gt; &amp;lt;/table&amp;gt; 
            
            &amp;lt;p&amp;gt;
               
            &amp;lt;/p&amp;gt;
            
            &amp;lt;p&amp;gt;
              The way in which people interact with business has changed. The entire customer service model is slowly changing and those who do not update their methods and ways will be left behind. In the US, the adoption of FourSquare and Gowalla has been picking up rapidly whereas in the UK its seen a slower adoption pace. One thing is for definite though, if you decide to provide offers to your customers/users of these services then you will drive traffic to your business and promote a better reputation with the digitalrati of the modern age.
            &amp;lt;/p&amp;gt;
            
            &amp;lt;p&amp;gt;
              This can provide to be key in the way in which your business is viewed. Trendy coffee bars in town centres are interested in seeing how they can use Gowalla and Foursquare to promote their business better. Promoting via one of these online services is like word-of-mouth on steroids. It’ll quickly get around the services and attract new people when they see their friends at your business.
            &amp;lt;/p&amp;gt;
            
            &amp;lt;p&amp;gt;
              Cafe&#39;s in the larger cities have already started offering free coffee and a muffin for the Mayor of their location. Believe me, no one will refuse a free muffin.
            &amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/tr&gt;&lt;/table&gt;</content>
  </entry>
  
  
  <entry>
    <title>Unified Reward Point System</title>
    
    <link href="https://dor.ky/unified-reward-point-system/" rel="alternate" type="text/html"/>
    
    <updated>2010-03-26T14:47:55-00:00</updated>
    <id>https://dor.ky/unified-reward-point-system/</id>
    <content type="html">&lt;p&gt;The system of &lt;a href=&quot;http://en.wikipedia.org/wiki/Loyalty_program&quot;&gt;rewarding customers&lt;/a&gt; with points, cards or discounts is a fairly standard practice amongst today’s modern business. This reward model is based around rewarding for purchases of goods and services and then allow these customers to choose a gift in return to reward their loyalty. The existing implementation are this reward network is singular in nature except for organisations such as Sainsbury’s &lt;a href=&quot;http://www.nectar.com/NectarHome.nectar&quot;&gt;nectar&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I believe that modern customers would be more beneficial to a system that was shared between businesses and then allowed the customer to take reward points to another company should they wish to do so. Providing the spread of reward was equal or near to equal over all participating organisations, then this model would be extremely beneficial to the customer who may for example not wish to have a gift from shop A, instead choosing a gift from shop B.&lt;/p&gt;
&lt;p&gt;The new age innovations that customers have access to such as the Internet, mobile phones and smart phones provide rich platforms for interaction with business. Devices such as mobile phones or smart phones that have Bluetooth could be registered against a user record and then through transmitters in store, promotional adverts or messages could be delivered via OBEX push when the user is nearby, as shown in the diagram below.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;img src=&quot;https://dor.ky/assets/images/old_content/67b1a29ec916bf1cd11cc36fcf00cbb2.jpg&quot; class=&quot;align-center img-border&quot; alt=&quot;&quot;&gt;
&lt;/p&gt;
&lt;p&gt;The transmitters shown above would be looking for known Bluetooth devices. Of course this would only happen if the handsets were configured to allow &lt;a href=&quot;http://en.wikipedia.org/wiki/OBject_EXchange&quot;&gt;OBEX&lt;/a&gt; items to be pushed. Alternatively, an email could be sent to the user (taken at opt-in) with discounts coupons for that day. Bluetooth’s proximity would allow tracking up to around 10 metres for most handsets which would be close enough for interaction. This would then drive customers to pursue interesting offers and lead to more sales.&lt;/p&gt;
&lt;p&gt;In the diagram below, relationships are displayed in colours so that it makes it easier to indicate what they represent. The yellow arrows show the relationships between a customer or group of customers and the businesses that they frequent. The purple arrows show the intranet-based or Internet-based link up to a central system. The blue arrow and read our indicate a link between the customer of being at home or on a smart device and interacting with the central system. This could be to engage in choosing a reward gift or simply updating their account details.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;img src=&quot;https://dor.ky/assets/images/old_content/c18364cc1e8f7fc27dc1713776373caa.jpg&quot; class=&quot;align-center img-border&quot; alt=&quot;&quot;&gt;
&lt;/p&gt;
&lt;p&gt;This system would also allow for flexibility and grouping users so that they may work together and obtain larger gifts. The biggest challenge in implementing a better, more advanced system would be gaining the participation of the larger organisations from which people choose to purchase their goods from. I do honestly believe that gap could be bridged then it would not be too far from the future to implement such a new system.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Platform vs Web Site</title>
    
    <link href="https://dor.ky/platform-vs-web-site/" rel="alternate" type="text/html"/>
    
    <updated>2010-03-24T15:47:21-00:00</updated>
    <id>https://dor.ky/platform-vs-web-site/</id>
    <content type="html">&lt;p&gt;Over the past six years we’ve seen major developments around the world in online services and computing. Traditional web sites such as Google, Amazon and eBay have now transformed into multinational platforms offering more than just a site to use. All of the services I’ve just named still provide their main web site, but isn’t it about time we started referring to them as platforms rather than sites. In my opinion, it is.&lt;/p&gt;
&lt;p&gt;You can do so much more than simply search with Google or buy with Amazon and eBay. I don’t see the naming and references changing any time soon, but this is a thought I’d like to see come to fruition. The traditional roots of each of these large platforms can never be forgotten but through their own research, development and improvements they’re providing excellent services for the rest of the world to use.&lt;/p&gt;
&lt;p&gt;In the more recent history, Twitter and Facebook have provided platforms for people to develop with which in turn created a boom for both enterprises. Its nice to see Facebook referring to their infrastructure and service as a platform, rather than a site. Perhaps others can follow suit, but I doubt it.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Apple OSX Temporary Fix for Dead Ethernet Adapter</title>
    
    <link href="https://dor.ky/apple-osx-temporary-fix-for-dead-ethernet-adapter/" rel="alternate" type="text/html"/>
    
    <updated>2010-03-20T11:07:43-00:00</updated>
    <id>https://dor.ky/apple-osx-temporary-fix-for-dead-ethernet-adapter/</id>
    <content type="html"></content>
  </entry>
  
  
  <entry>
    <title>Really, robots.txt is There for a Reason</title>
    
    <link href="https://dor.ky/really-robotstxt-is-there-for-a-reason/" rel="alternate" type="text/html"/>
    
    <updated>2010-03-06T14:31:08-00:00</updated>
    <id>https://dor.ky/really-robotstxt-is-there-for-a-reason/</id>
    <content type="html">&lt;p&gt;Quite a while back now in Internet history a system called ‘&lt;a href=&quot;http://www.robotstxt.org/&quot;&gt;robots.txt&lt;/a&gt;’ was introduced to control the content that web crawlers and services are permissible to crawl. This file details a map which denotes what crawler/bot is allowed to crawl a site. At &lt;a href=&quot;http://www.tweekly.fm/&quot;&gt;tweekly.fm&lt;/a&gt; I deal with a lot of user traffic and the complicated nature of our queries means that its quite intensive to generate the user pages.&lt;/p&gt;
&lt;p&gt;There are multiple levels of caching and memcache is there too but even under peak times we still have to serve pages to users. The most infuriating thing is during the period in which we send tweets out each day for users, we get bombarded with requests from crawlers and bots. This slows both our service and our processing down but if the crawlers in question were to honour robots.txt as they should do then this wouldn’t even be an issue. It wouldn’t even be too bad if requests were staggered out over a period of time.&lt;/p&gt;
&lt;p&gt;The worst offenders at first glance are TweetMeme, Radian6, PostRank, TwittUrls, MetaURI, Twingly, Page-Store &amp;amp; Chainn.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Tweekly.fm Featured in a Book</title>
    
    <link href="https://dor.ky/tweeklyfm-featured-in-a-book/" rel="alternate" type="text/html"/>
    
    <updated>2010-03-05T12:01:14-00:00</updated>
    <id>https://dor.ky/tweeklyfm-featured-in-a-book/</id>
    <content type="html">&lt;p&gt;Sometime last week I was talking to Simon about &lt;a href=&quot;http://tweekly.fm/&quot;&gt;Tweekly.fm&lt;/a&gt; and he informed me that &lt;a href=&quot;http://tweekly.fm/&quot;&gt;Tweekly.fm&lt;/a&gt; was going to be feature in a book that’s being written by &lt;a href=&quot;http://twitter.com/GarinKilpatrick&quot;&gt;Garin Kilpatrick&lt;/a&gt;. Garin’s &lt;a href=&quot;http://twitter.com/GarinKilpatrick/twitter-tools&quot;&gt;book&lt;/a&gt; will document tools to be used with Twitter and we’re happy that we’re going to be featured. Its nice to see that the service being provided to end users is a good one and that we’re being recognised as a useful tool.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Caching &amp;#038; ADOdb for Tweekly.fm</title>
    
    <link href="https://dor.ky/caching-adodb-for-tweeklyfm/" rel="alternate" type="text/html"/>
    
    <updated>2010-02-26T21:59:24-00:00</updated>
    <id>https://dor.ky/caching-adodb-for-tweeklyfm/</id>
    <content type="html">&lt;p&gt;The best thing about building a project that gets popular is the same as the worst things about a project that grows rapidly. &lt;a href=&quot;http://tweekly.fm/&quot;&gt;Tweekly.fm&lt;/a&gt; is currently gaining 1,500 users per month most of which decide to publish on a Sunday. This increases the load and run time of the delivery engine that pushes tweets outbound. The other side of an increased user base is that user pages get more popular. Although this is a good thing overall and shows our popularity – it also has its downsides.&lt;/p&gt;
&lt;p&gt;The queries to show simple people and shared by counts are expensive to run. We’re indexing just short of 25,000 user records and running the queries in the original way brought the servers down to a sluggish speed. My response to this was to rewrite the entire user pages and introduce caching on a couple of levels.&lt;/p&gt;
&lt;p&gt;The diagram below shows the original connections between our servers and our users. As the diagram shows, there was no caching present through the system. This presented problems under load and ended up with the user pages of the site being temporarily postponed.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;img src=&quot;https://dor.ky/assets/images/old_content/26c93f90c1a08eee6829b8d91966a066.jpg&quot; alt=&quot;Uncached&quot; class=&quot;img-border&quot;&gt;
&lt;/p&gt;
&lt;p&gt;After a little research and crunching of numbers I came down to the conclusion that caching points at both the database server and the website (abstraction layer). Implementing the &lt;a href=&quot;http://adodb.sourceforge.net/&quot;&gt;ADOdb&lt;/a&gt; layer underneath the existing database links has proven to be a great success. Its boosted response times over 300%. The next diagram shows the new caching points added the the system.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;img src=&quot;https://dor.ky/assets/images/old_content/a1452d061838f1bd93e270ea044d5e87.jpg&quot; alt=&quot;Cached&quot; class=&quot;img-border&quot;&gt;
&lt;/p&gt;
&lt;p&gt;Point A is the abstraction layer at the site level. At peak times, the queries issued here are cached for an hour. This scales back to 30 minutes at low load times. Point B is the connection between the web server and database server. Queries are cached at the database constantly via the &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.1/en/query-cache.html&quot;&gt;MySQL Query Cache&lt;/a&gt;. Finally Point C is the connection to the Twitter API. All calls are cached for 30 minutes where possible, but due to the nature of the API and service in general I’m not currently caching too much here. What is not shown on the diagram is the connection to the &lt;a href=&quot;http://last.fm/&quot;&gt;last.fm&lt;/a&gt; API because this data is automatically cached and updated when needed.&lt;/p&gt;
&lt;h3 id=&quot;effects-of-changes-for-users&quot;&gt;Effects of Changes for Users&lt;/h3&gt;
&lt;p&gt;The effects of these changes will be noticeable by all users because the front-end of the site will be a lot snappier and responses should be quicker too. Hopefully this is just one of many changes that can improve the system for everyone.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Social Traffic Alerting</title>
    
    <link href="https://dor.ky/social-traffic-alerting/" rel="alternate" type="text/html"/>
    
    <updated>2010-02-25T10:14:09-00:00</updated>
    <id>https://dor.ky/social-traffic-alerting/</id>
    <content type="html">&lt;p&gt;I spent some time yesterday extending the &lt;a href=&quot;http://dor.ky/projects/stoketraffic&quot;&gt;StokeTraffic&lt;/a&gt; platform to include support for eye witness reports provided by users of the service. This now means that the service will include real time eye witness reports of problems and conditions of the roads in and around Stoke on Trent. All users are invited to participate in this extension of the service by using the new feature. If you’re travelling in or around Stoke on Trent and spot a problem then you can alert us by posting a tweet similar to the following:&lt;/p&gt;
&lt;div class=&quot;message info&quot;&gt;
  @stoketraffic rep A500 Extremely busy due to congestion
&lt;/div&gt;
&lt;p&gt;If your report is accepted it’ll be posted live within a few moments. Please be aware that reports are limited to 100 characters and there are measures in place to prevent abuse to this service. I’m looking for suggestions, features and also of any issues. Get in contact with me &lt;a href=&quot;https://dor.ky/contact&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Geocaching.com Storing Plaintext Passwords</title>
    
    <link href="https://dor.ky/geocachingcom-storing-plaintext-passwords/" rel="alternate" type="text/html"/>
    
    <updated>2010-02-04T23:06:17-00:00</updated>
    <id>https://dor.ky/geocachingcom-storing-plaintext-passwords/</id>
    <content type="html">&lt;p&gt;I completely found myself in shock earlier today when I had to use the ‘forgotten password’ feature on &lt;a href=&quot;http://geocaching.com/&quot;&gt;geocaching.com&lt;/a&gt;. To my complete amazement, they emailed my password back to me in plaintext. Now, bearing in mind that most of their site is basic in features I’m sure they haven’t generated their own two way encryption so that means they’re storing passwords plaintext which in this modern age is suicidal.&lt;/p&gt;
&lt;p&gt;I simply couldn’t believe it, I hope they can prove me wrong but I’m almost sure they storing them plaintext. Please, someone from &lt;a href=&quot;http://geocaching.com/&quot;&gt;geocaching.com&lt;/a&gt; contact me and tell me you have some space age encryption going. Until then, I’m changing my password to something retarded.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>LaFonera as a Wifi Bridge/Repeater</title>
    
    <link href="https://dor.ky/lafonera-as-a-wifi-bridge-repeater/" rel="alternate" type="text/html"/>
    
    <updated>2010-01-17T13:47:08-00:00</updated>
    <id>https://dor.ky/lafonera-as-a-wifi-bridge-repeater/</id>
    <content type="html">&lt;p&gt;This is a screenshot of the bandwidth usage for the Fonera router I flashed last week. Everything seems to be working fine. A couple of PDF documents that I found useful can be downloaded &lt;a href=&quot;https://dor.ky/assets/images/old_content/kolofonium_tutorial.pdf&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://dor.ky/assets/images/old_content/lafonera.pdf&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dor.ky/assets/images/old_content/e381faebce12f2e363e04d0e8290d3e6.jpg&quot; alt=&quot;ddwrt bandwidth&quot;&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Last.fm Auto-Tweeting</title>
    
    <link href="https://dor.ky/lastfm-auto-tweeting/" rel="alternate" type="text/html"/>
    
    <updated>2010-01-17T03:12:43-00:00</updated>
    <id>https://dor.ky/lastfm-auto-tweeting/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This has been moved to &lt;a href=&quot;http://tweekly.fm/&quot;&gt;http://tweekly.fm&lt;/a&gt; as I’ve rewritten and redeveloped the tweekly system.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Also, there is a Facebook version here at &lt;a href=&quot;http://laststat.us/&quot;&gt;laststat.us&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left&quot;&gt;
  &lt;strike&gt;I&#39;ve just finished the beta of my autotweeting&lt;/strike&gt;&lt;a href=&quot;http://last.fm/&quot;&gt;&lt;strike&gt; last.fm&lt;/strike&gt;&lt;/a&gt;&lt;strike&gt; statistics system. It&#39;ll take your last.fm top artists and publish them to Twitter on a day of your choosing.You can sign up for the &lt;/strike&gt;&lt;a href=&quot;http://lastfm.dor.ky/&quot;&gt;&lt;strike&gt;beta here&lt;/strike&gt;&lt;/a&gt;&lt;strike&gt;.&lt;/strike&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left&quot;&gt;
  If you have any problems or encounter errors while using the system then please contact me as soon as you can do at &lt;a href=&quot;mailto:scott@dor.ky&quot;&gt;scott@dor.ky&lt;/a&gt;.
&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Hacking a Fonera Router</title>
    
    <link href="https://dor.ky/hacking-a-fonera-router/" rel="alternate" type="text/html"/>
    
    <updated>2010-01-15T20:04:30-00:00</updated>
    <id>https://dor.ky/hacking-a-fonera-router/</id>
    <content type="html">&lt;p&gt;A few people have asked about more details for the wireless bridge I’ve set up within my local network. You can find more information &lt;a href=&quot;http://dor.ky/hacking-a-fonera-router&quot;&gt;about it here&lt;/a&gt;. Its a pretty simple process and you end up with a router running DDWRT.&lt;/p&gt;
&lt;p&gt;I’ve got it set up to bridge the ethernet port into the main wireless network here.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Google Latitude API Non-Existance</title>
    
    <link href="https://dor.ky/google-latitude-api-non-existance/" rel="alternate" type="text/html"/>
    
    <updated>2009-12-10T19:23:24-00:00</updated>
    <id>https://dor.ky/google-latitude-api-non-existance/</id>
    <content type="html">&lt;p&gt;I’ve just written a request for more information from Google as I’m astounded to find no accessible API for Latitude. I find that completely shocking on their part.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’ve looked on the AppSpot site and here in the group and I’ve not seen a definitive answer as such to this question. Is there an accessible API to update my location on Latitude? I already have my location via GPS elsewhere and would very much like to bridge this over the Latitude and update my location there.&lt;/p&gt;
&lt;p&gt;I see that at present, this is not possible through existing Latitude services, however I’m interested in knowing whether or not Google plans to introduce this in future and if so – a possible time frame for doing so. I have an application that I would like to use this functionality in.&lt;/p&gt;
&lt;p&gt;Scott.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can see the actual post and follow it &lt;a href=&quot;http://www.google.com/support/forum/p/Google+Mobile/thread?tid=422f1e85d95f4e1f&amp;amp;hl=en&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
</feed>
